[
  {
    "path": ".github/CODEOWNERS",
    "content": "# See https://help.github.com/articles/about-codeowners/\n# for more info about CODEOWNERS file\n\n*       @urfave/cli\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: ask a question\nabout: ask a question - assume stackoverflow's guidelines apply here\ntitle: your question title goes here\nlabels: 'kind/question, status/triage, area/v2'\nassignees: ''\n\n---\n\nmy question is...\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v1-bug-report.md",
    "content": "---\nname: v1 bug report\nabout: Create a report to help us fix v1 bugs\ntitle: 'your bug title goes here'\nlabels: 'kind/bug, status/triage, area/v1'\nassignees: ''\n\n---\n\n## My urfave/cli version is\n\n_**( Put the version of urfave/cli that you are using here )**_\n\n## Checklist\n\n- [ ] Are you running the latest v1 release? The list of releases is [here](https://github.com/urfave/cli/releases).\n- [ ] Did you check the manual for your release? The v1 manual is [here](https://cli.urfave.org/v1/getting-started/).\n- [ ] Did you perform a search about this problem? Here's the [GitHub guide](https://help.github.com/en/github/managing-your-work-on-github/using-search-to-filter-issues-and-pull-requests) about searching.\n\n## Dependency Management\n\n<!--\n  Delete any of the following that do not apply:\n-->\n\n- My project is using go modules.\n- My project is using vendoring.\n- My project is automatically downloading the latest version.\n- I am unsure of what my dependency management setup is.\n\n## Describe the bug\n\nA clear and concise description of what the bug is.\n\n## To reproduce\n\nDescribe the steps or code required to reproduce the behavior\n\n## Observed behavior\n\nWhat did you see happen immediately after the reproduction steps\nabove?\n\n## Expected behavior\n\nWhat would you have expected to happen immediately after the\nreproduction steps above?\n\n## Additional context\n\nAdd any other context about the problem here.\n\nIf the issue relates to a specific open source GitHub repo, please\nlink that repo here.\n\nIf you can reproduce this issue with a public CI system, please\nlink a failing build here.\n\n## Want to fix this yourself?\n\nWe'd love to have more contributors on this project! If the fix for\nthis bug is easily explained and very small, feel free to create a\npull request for it. You'll want to base the PR off the `v1`\nbranch, all `v1` bug fix releases will be made from that branch.\n\n## Run `go version` and paste its output here\n\n```\n# paste `go version` output in here\n```\n\n## Run `go env` and paste its output here\n\n```\n# paste `go env` output in here\n```\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v2-bug-report.md",
    "content": "---\nname: v2 bug report\nabout: Create a report to help us fix v2 bugs\ntitle: 'your bug title goes here'\nlabels: 'kind/bug, area/v2, status/triage'\nassignees: ''\n\n---\n\n## My urfave/cli version is\n\n_**( Put the version of urfave/cli that you are using here )**_\n\n## Checklist\n\n- [ ] Are you running the latest v2 release? The list of releases is [here](https://github.com/urfave/cli/releases).\n- [ ] Did you check the manual for your release? The v2 manual is [here](https://cli.urfave.org/v2/getting-started/)\n- [ ] Did you perform a search about this problem? Here's the [GitHub guide](https://help.github.com/en/github/managing-your-work-on-github/using-search-to-filter-issues-and-pull-requests) about searching.\n\n## Dependency Management\n\n<!--\n  Delete any of the following that do not apply:\n-->\n\n- My project is using go modules.\n- My project is using vendoring.\n- My project is automatically downloading the latest version.\n- I am unsure of what my dependency management setup is.\n\n## Describe the bug\n\nA clear and concise description of what the bug is.\n\n## To reproduce\n\nDescribe the steps or code required to reproduce the behavior\n\n## Observed behavior\n\nWhat did you see happen immediately after the reproduction steps\nabove?\n\n## Expected behavior\n\nWhat would you have expected to happen immediately after the\nreproduction steps above?\n\n## Additional context\n\nAdd any other context about the problem here.\n\nIf the issue relates to a specific open source GitHub repo, please\nlink that repo here.\n\nIf you can reproduce this issue with a public CI system, please\nlink a failing build here.\n\n## Want to fix this yourself?\n\nWe'd love to have more contributors on this project! If the fix for\nthis bug is easily explained and very small, feel free to create a\npull request for it.\n\n## Run `go version` and paste its output here\n\n```\n# paste `go version` output in here\n```\n\n## Run `go env` and paste its output here\n\n```\n# paste `go env` output in here\n```\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v3-bug-report.md",
    "content": "---\nname: v3 bug report\nabout: Create a report to help us fix v3 bugs\ntitle: 'your bug title goes here'\nlabels: 'kind/bug, area/v3, status/triage'\nassignees: ''\n\n---\n\n## My urfave/cli version is\n\n_**( Put the version of urfave/cli that you are using here )**_\n\n## Checklist\n\n- [ ] Are you running the latest v3 release? The list of releases is [here](https://github.com/urfave/cli/releases).\n- [ ] Did you check the manual for your release? The v3 manual is [here](https://cli.urfave.org/v3/getting-started/)\n- [ ] Did you perform a search about this problem? Here's the [GitHub guide](https://help.github.com/en/github/managing-your-work-on-github/using-search-to-filter-issues-and-pull-requests) about searching.\n\n## Dependency Management\n\n<!--\n  Delete any of the following that do not apply:\n-->\n\n- My project is using go modules.\n- My project is using vendoring.\n- My project is automatically downloading the latest version.\n- I am unsure of what my dependency management setup is.\n\n## Describe the bug\n\nA clear and concise description of what the bug is.\n\n## To reproduce\n\nDescribe the steps or code required to reproduce the behavior\n\n## Observed behavior\n\nWhat did you see happen immediately after the reproduction steps\nabove?\n\n## Expected behavior\n\nWhat would you have expected to happen immediately after the\nreproduction steps above?\n\n## Additional context\n\nAdd any other context about the problem here.\n\nIf the issue relates to a specific open source GitHub repo, please\nlink that repo here.\n\nIf you can reproduce this issue with a public CI system, please\nlink a failing build here.\n\n## Want to fix this yourself?\n\nWe'd love to have more contributors on this project! If the fix for\nthis bug is easily explained and very small, feel free to create a\npull request for it.\n\n## Run `go version` and paste its output here\n\n```\n# paste `go version` output in here\n```\n\n## Run `go env` and paste its output here\n\n```\n# paste `go env` output in here\n```\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v3-feature-request.md",
    "content": "---\nname: v3 feature request\nabout: Suggest an improvement to go into v3\ntitle: 'your feature title goes here'\nlabels: 'type/feature, area/v3, status/triage'\nassignees: ''\n\n---\n\n## Checklist\n\n* [ ] Are you running the latest v3 release? The list of releases is [here](https://github.com/urfave/cli/releases).\n* [ ] Did you check the manual for your release? The v3 manual is [here](https://github.com/urfave/cli/blob/main/docs/v3/index.md).\n* [ ] Did you perform a search about this feature? Here's the [GitHub guide](https://help.github.com/en/github/managing-your-work-on-github/using-search-to-filter-issues-and-pull-requests) about searching.\n\n## What problem does this solve?\n\nA clear and concise description of what problem this feature would solve. For example:\n\n- needing to type out the full flag name takes a long time, so I\n  would like to suggest adding auto-complete\n- I use (osx, windows, linux) and would like support for (some\n  existing feature) to be extended to my platform\n- the terminal output for a particular error case is confusing, and\n  I think it could be improved\n\n## Solution description\n\nA detailed description of what you want to happen.\n\n## Describe alternatives you've considered\n\nA clear and concise description of any alternative solutions or\nfeatures you've considered.\n"
  },
  {
    "path": ".github/codecov.yml",
    "content": "comment: false\ncoverage:\n  status:\n    project:\n      default:\n        threshold: 5%\n    patch:\n      default:\n        threshold: 5%\nignore:\n  - examples\n  - scripts\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: gomod\n    directory: /\n    schedule:\n      interval: weekly\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: weekly\n  - package-ecosystem: pip\n    directory: /\n    schedule:\n      interval: weekly\n    groups:\n      python-packages:\n        patterns: [\"*\"]\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!--\n  This template provides some ideas of things to include in your PR description.\n  To start, try providing a short summary of your changes in the Title above.\n  If a section of the PR template does not apply to this PR, then delete that section.\n -->\n\n## What type of PR is this?\n\n_(REQUIRED)_\n\n<!--\n  Delete any of the following that do not apply:\n -->\n\n- bug\n- cleanup\n- documentation\n- feature\n\n## What this PR does / why we need it:\n\n_(REQUIRED)_\n\n<!--\n  What goal is this change working towards?\n  Provide a bullet pointed summary of how each file was changed.\n  Briefly explain any decisions you made with respect to the changes.\n  Include anything here that you didn't include in *Release Notes*\n  above, such as changes to CI or changes to internal methods.\n-->\n\n## Which issue(s) this PR fixes:\n\n_(REQUIRED)_\n\n<!--\nIf this PR fixes one of more issues, list them here.\nOne line each, like so:\n\nFixes #123\nFixes #39\n-->\n\n## Special notes for your reviewer:\n\n_(fill-in or delete this section)_\n\n<!--\n   Is there any particular feedback you would / wouldn't like?\n   Which parts of the code should reviewers focus on?\n-->\n\n## Testing\n\n_(fill-in or delete this section)_\n\n<!--\n  Describe how you tested this change.\n-->\n\n## Release Notes\n\n_(REQUIRED)_\n<!--\n  If this PR makes user facing changes, please describe them here. This\n  description will be copied into the release notes/changelog, whenever the\n  next version is released. Keep this section short, and focus on high level\n  changes.\n\n  Put your text between the block. To omit notes, use NONE within the block.\n-->\n\n```release-note\n\n```\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Run lints\n\non:\n  push:\n    tags:\n      - v3.*\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n\npermissions:\n  contents: read\n\njobs:\n  golangci-lint:\n    runs-on: ubuntu-24.04\n\n    steps:\n      - name: Clone repository\n        uses: actions/checkout@v6\n\n      - name: Set up Go\n        uses: actions/setup-go@v6\n        with:\n          go-version: stable\n\n      - name: Run golangci-lint\n        uses: golangci/golangci-lint-action@v9\n        with:\n          version: latest\n"
  },
  {
    "path": ".github/workflows/publish-docs.yml",
    "content": "name: publish docs\n\non:\n  push:\n    branches:\n      - main\n    tags:\n      - v3.*\n\npermissions:\n  contents: read\n\njobs:\n  test-docs:\n    name: test-docs\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Set up Go\n        uses: actions/setup-go@v6\n        with:\n          go-version: stable\n\n      - name: Set PATH\n        run: echo \"${GITHUB_WORKSPACE}/.local/bin\" >>\"${GITHUB_PATH}\"\n\n      - run: make ensure-gfmrun\n\n      - run: make gfmrun\n        env:\n          FLAGS: --walk docs/v3/\n\n      - run: make diffcheck\n\n  publish:\n    permissions:\n      contents: write\n    if: startswith(github.ref, 'refs/tags/')\n    name: publish\n    needs: [test-docs]\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - uses: actions/setup-python@v6\n        with:\n          python-version: '3.13'\n          cache: pip\n          cache-dependency-path: mkdocs-requirements.txt\n\n      - name: Ensure mkdocs is available\n        run: make ensure-mkdocs\n\n      - name: Set mkdocs remote\n        run: make set-mkdocs-remote\n        env:\n          MKDOCS_REMOTE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Deploy via mkdocs\n        run: make deploy-mkdocs\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Run tests\n\non:\n  push:\n    branches:\n      - main\n    tags:\n      - v3.*\n  pull_request:\n    branches:\n      - main\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ubuntu-24.04, macos-15, windows-2025]\n        go: [stable, oldstable]\n\n    name: ${{ matrix.os }} @ Go ${{ matrix.go }}\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Set up Go\n        uses: actions/setup-go@v6\n        with:\n          go-version: ${{ matrix.go }}\n\n      - name: Set PATH\n        run: echo \"${GITHUB_WORKSPACE}/.local/bin\" >>\"${GITHUB_PATH}\"\n\n      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'\n        run: make ensure-goimports\n\n      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'\n        run: make lint\n\n      - run: make vet\n      - run: make test\n      - run: make check-binary-size\n\n      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'\n        run: make generate\n\n      - run: make diffcheck\n\n      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'\n        run: make v3diff\n\n      - if: success() && matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          fail_ci_if_error: true\n          verbose: true\n"
  },
  {
    "path": ".gitignore",
    "content": "*.coverprofile\n*.exe\n*.orig\n.*envrc\n.envrc\n.idea\n/.local/\n/site/\ncoverage.txt\nexamples/*/built-example\nvendor\n"
  },
  {
    "path": ".golangci.yaml",
    "content": "version: \"2\"\n\nformatters:\n  enable:\n    - gofumpt\n\nlinters:\n  enable:\n    - makezero\n    - misspell\n  exclusions:\n    presets:\n      - std-error-handling\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\neducation, socio-economic status, nationality, personal appearance, race,\nreligion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting urfave-governance@googlegroups.com, a members-only group\nthat is world-postable. All complaints will be reviewed and investigated and\nwill result in a response that is deemed necessary and appropriate to the\ncircumstances. The project team is obligated to maintain confidentiality with\nregard to the reporter of an incident. Further details of specific enforcement\npolicies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# NOTE: this Makefile is meant to provide a simplified entry point for humans to\n# run all of the critical steps to verify one's changes are harmonious in\n# nature. Keeping target bodies to one line each and abstaining from make magic\n# are very important so that maintainers and contributors can focus their\n# attention on files that are primarily Go.\n\nGO_RUN_BUILD := go run scripts/build.go\n\n.PHONY: all\nall: generate vet test check-binary-size gfmrun\n\n# NOTE: this is a special catch-all rule to run any of the commands\n# defined in scripts/build.go with optional arguments passed\n# via GFLAGS (global flags) and FLAGS (command-specific flags), e.g.:\n#\n#   $ make test GFLAGS='--packages cli'\n%:\n\t$(GO_RUN_BUILD) $(GFLAGS) $* $(FLAGS)\n\n.PHONY: docs\ndocs:\n\tmkdocs build\n\n.PHONY: serve-docs\nserve-docs:\n\tmkdocs serve\n"
  },
  {
    "path": "README.md",
    "content": "# Welcome to urfave/cli\n\n[![Go Reference][goreference_badge]][goreference_link]\n[![Go Report Card][goreportcard_badge]][goreportcard_link]\n[![codecov][codecov_badge]][codecov_link]\n[![Tests status][test_badge]][test_link]\n\nurfave/cli is a **declarative**, simple, fast, and fun package for building\ncommand line tools in Go featuring:\n\n- commands and subcommands with alias and prefix match support\n- flexible and permissive help system\n- dynamic shell completion for `bash`, `zsh`, `fish`, and `powershell`\n- no dependencies except Go standard library\n- input flags for simple types, slices of simple types, time, duration, and\n  others\n- compound short flag support (`-a` `-b` `-c` can be shortened to `-abc`)\n- documentation generation in `man` and Markdown (supported via the\n  [`urfave/cli-docs`][urfave/cli-docs] module)\n- input lookup from:\n  - environment variables\n  - plain text files\n  - structured file formats (supported via the\n    [`urfave/cli-altsrc`][urfave/cli-altsrc] module)\n\n## Documentation\n\nSee the hosted documentation website at <https://cli.urfave.org>. Contents of\nthis website are built from the [`./docs`](./docs) directory.\n\n## Support\n\nCheck the [Q&A discussions]. If you don't find answer to your question, [create\na new discussion].\n\nIf you found a bug or have a feature request, [create a new issue].\n\nPlease keep in mind that this project is run by unpaid volunteers.\n\n### License\n\nSee [`LICENSE`](./LICENSE).\n\n[test_badge]: https://github.com/urfave/cli/actions/workflows/test.yml/badge.svg\n[test_link]: https://github.com/urfave/cli/actions/workflows/test.yml\n[goreference_badge]: https://pkg.go.dev/badge/github.com/urfave/cli/v3.svg\n[goreference_link]: https://pkg.go.dev/github.com/urfave/cli/v3\n[goreportcard_badge]: https://goreportcard.com/badge/github.com/urfave/cli/v3\n[goreportcard_link]: https://goreportcard.com/report/github.com/urfave/cli/v3\n[codecov_badge]: https://codecov.io/gh/urfave/cli/branch/main/graph/badge.svg?token=t9YGWLh05g\n[codecov_link]: https://codecov.io/gh/urfave/cli\n[Q&A discussions]: https://github.com/urfave/cli/discussions/categories/q-a\n[create a new discussion]: https://github.com/urfave/cli/discussions/new?category=q-a\n[urfave/cli-docs]: https://github.com/urfave/cli-docs\n[urfave/cli-altsrc]: https://github.com/urfave/cli-altsrc\n[create a new issue]: https://github.com/urfave/cli/issues/new/choose\n"
  },
  {
    "path": "args.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Args interface {\n\t// Get returns the nth argument, or else a blank string\n\tGet(n int) string\n\t// First returns the first argument, or else a blank string\n\tFirst() string\n\t// Tail returns the rest of the arguments (not the first one)\n\t// or else an empty string slice\n\tTail() []string\n\t// Len returns the length of the wrapped slice\n\tLen() int\n\t// Present checks if there are any arguments present\n\tPresent() bool\n\t// Slice returns a copy of the internal slice\n\tSlice() []string\n}\n\ntype stringSliceArgs struct {\n\tv []string\n}\n\nfunc (a *stringSliceArgs) Get(n int) string {\n\tif len(a.v) > n {\n\t\treturn a.v[n]\n\t}\n\treturn \"\"\n}\n\nfunc (a *stringSliceArgs) First() string {\n\treturn a.Get(0)\n}\n\nfunc (a *stringSliceArgs) Tail() []string {\n\tif a.Len() >= 2 {\n\t\ttail := a.v[1:]\n\t\tret := make([]string, len(tail))\n\t\tcopy(ret, tail)\n\t\treturn ret\n\t}\n\n\treturn []string{}\n}\n\nfunc (a *stringSliceArgs) Len() int {\n\treturn len(a.v)\n}\n\nfunc (a *stringSliceArgs) Present() bool {\n\treturn a.Len() != 0\n}\n\nfunc (a *stringSliceArgs) Slice() []string {\n\tret := make([]string, len(a.v))\n\tcopy(ret, a.v)\n\treturn ret\n}\n\n// Argument captures a positional argument that can\n// be parsed\ntype Argument interface {\n\t// which this argument can be accessed using the given name\n\tHasName(string) bool\n\n\t// Parse the given args and return unparsed args and/or error\n\tParse([]string) ([]string, error)\n\n\t// The usage template for this argument to use in help\n\tUsage() string\n\n\t// The Value of this Arg\n\tGet() any\n}\n\n// AnyArguments to differentiate between no arguments(nil) vs aleast one\nvar AnyArguments = []Argument{\n\t&StringArgs{\n\t\tMax: -1,\n\t},\n}\n\ntype ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName        string `json:\"name\"`      // the name of this argument\n\tValue       T      `json:\"value\"`     // the default value of this argument\n\tDestination *T     `json:\"-\"`         // the destination point for this argument\n\tUsageText   string `json:\"usageText\"` // the usage text to show\n\tConfig      C      `json:\"config\"`    // config for this argument similar to Flag Config\n\n\tvalue *T\n}\n\nfunc (a *ArgumentBase[T, C, VC]) HasName(s string) bool {\n\treturn s == a.Name\n}\n\nfunc (a *ArgumentBase[T, C, VC]) Usage() string {\n\tif a.UsageText != \"\" {\n\t\treturn a.UsageText\n\t}\n\n\tusageFormat := \"%[1]s\"\n\treturn fmt.Sprintf(usageFormat, a.Name)\n}\n\nfunc (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {\n\ttracef(\"calling arg%[1] parse with args %[2]\", a.Name, s)\n\n\tvar vc VC\n\tvar t T\n\tvalue := vc.Create(a.Value, &t, a.Config)\n\ta.value = &t\n\n\ttracef(\"attempting arg%[1] parse\", &a.Name)\n\tif len(s) > 0 {\n\t\tif err := value.Set(s[0]); err != nil {\n\t\t\treturn s, fmt.Errorf(\"invalid value %q for argument %s: %v\", s[0], a.Name, err)\n\t\t}\n\t\t*a.value = value.Get().(T)\n\t\ttracef(\"set arg%[1] one value\", a.Name, *a.value)\n\t}\n\n\tif a.Destination != nil {\n\t\ttracef(\"setting destination\")\n\t\t*a.Destination = *a.value\n\t}\n\n\tif len(s) > 0 {\n\t\treturn s[1:], nil\n\t}\n\treturn s, nil\n}\n\nfunc (a *ArgumentBase[T, C, VC]) Get() any {\n\tif a.value != nil {\n\t\treturn *a.value\n\t}\n\treturn a.Value\n}\n\n// ArgumentsBase is a base type for slice arguments\ntype ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName        string `json:\"name\"`      // the name of this argument\n\tValue       T      `json:\"value\"`     // the default value of this argument\n\tDestination *[]T   `json:\"-\"`         // the destination point for this argument\n\tUsageText   string `json:\"usageText\"` // the usage text to show\n\tMin         int    `json:\"minTimes\"`  // the min num of occurrences of this argument\n\tMax         int    `json:\"maxTimes\"`  // the max num of occurrences of this argument, set to -1 for unlimited\n\tConfig      C      `json:\"config\"`    // config for this argument similar to Flag Config\n\n\tvalues []T\n}\n\nfunc (a *ArgumentsBase[T, C, VC]) HasName(s string) bool {\n\treturn s == a.Name\n}\n\nfunc (a *ArgumentsBase[T, C, VC]) Usage() string {\n\tif a.UsageText != \"\" {\n\t\treturn a.UsageText\n\t}\n\n\tusageFormat := \"\"\n\tif a.Min == 0 {\n\t\tif a.Max == 1 {\n\t\t\tusageFormat = \"[%[1]s]\"\n\t\t} else {\n\t\t\tusageFormat = \"[%[1]s ...]\"\n\t\t}\n\t} else {\n\t\tusageFormat = \"%[1]s [%[1]s ...]\"\n\t}\n\treturn fmt.Sprintf(usageFormat, a.Name)\n}\n\nfunc (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error) {\n\ttracef(\"calling arg%[1] parse with args %[2]\", &a.Name, s)\n\tif a.Max == 0 {\n\t\treturn s, fmt.Errorf(\"args %s has max 0, not parsing argument\", a.Name)\n\t}\n\tif a.Max != -1 && a.Min > a.Max {\n\t\treturn s, fmt.Errorf(\"args %s has min[%d] > max[%d], not parsing argument\", a.Name, a.Min, a.Max)\n\t}\n\n\tcount := 0\n\tvar vc VC\n\tvar t T\n\tvalue := vc.Create(a.Value, &t, a.Config)\n\ta.values = []T{}\n\n\ttracef(\"attempting arg%[1] parse\", &a.Name)\n\tfor _, arg := range s {\n\t\tif err := value.Set(arg); err != nil {\n\t\t\treturn s, fmt.Errorf(\"invalid value %q for argument %s: %v\", arg, a.Name, err)\n\t\t}\n\t\ttracef(\"set arg%[1] one value\", &a.Name, value.Get().(T))\n\t\ta.values = append(a.values, value.Get().(T))\n\t\tcount++\n\t\tif count >= a.Max && a.Max > -1 {\n\t\t\tbreak\n\t\t}\n\t}\n\tif count < a.Min {\n\t\treturn s, fmt.Errorf(\"sufficient count of arg %s not provided, given %d expected %d\", a.Name, count, a.Min)\n\t}\n\n\tif a.Destination != nil {\n\t\ttracef(\"appending destination\")\n\t\t*a.Destination = a.values // append(*a.Destination, a.values...)\n\t}\n\n\treturn s[count:], nil\n}\n\nfunc (a *ArgumentsBase[T, C, VC]) Get() any {\n\tif a.values != nil {\n\t\treturn a.values\n\t}\n\treturn []T{}\n}\n\ntype (\n\tFloatArg      = ArgumentBase[float64, NoConfig, floatValue[float64]]\n\tFloat32Arg    = ArgumentBase[float32, NoConfig, floatValue[float32]]\n\tFloat64Arg    = ArgumentBase[float64, NoConfig, floatValue[float64]]\n\tIntArg        = ArgumentBase[int, IntegerConfig, intValue[int]]\n\tInt8Arg       = ArgumentBase[int8, IntegerConfig, intValue[int8]]\n\tInt16Arg      = ArgumentBase[int16, IntegerConfig, intValue[int16]]\n\tInt32Arg      = ArgumentBase[int32, IntegerConfig, intValue[int32]]\n\tInt64Arg      = ArgumentBase[int64, IntegerConfig, intValue[int64]]\n\tStringArg     = ArgumentBase[string, StringConfig, stringValue]\n\tStringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap]\n\tTimestampArg  = ArgumentBase[time.Time, TimestampConfig, timestampValue]\n\tUintArg       = ArgumentBase[uint, IntegerConfig, uintValue[uint]]\n\tUint8Arg      = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]]\n\tUint16Arg     = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]]\n\tUint32Arg     = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]\n\tUint64Arg     = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]\n\n\tFloatArgs     = ArgumentsBase[float64, NoConfig, floatValue[float64]]\n\tFloat32Args   = ArgumentsBase[float32, NoConfig, floatValue[float32]]\n\tFloat64Args   = ArgumentsBase[float64, NoConfig, floatValue[float64]]\n\tIntArgs       = ArgumentsBase[int, IntegerConfig, intValue[int]]\n\tInt8Args      = ArgumentsBase[int8, IntegerConfig, intValue[int8]]\n\tInt16Args     = ArgumentsBase[int16, IntegerConfig, intValue[int16]]\n\tInt32Args     = ArgumentsBase[int32, IntegerConfig, intValue[int32]]\n\tInt64Args     = ArgumentsBase[int64, IntegerConfig, intValue[int64]]\n\tStringArgs    = ArgumentsBase[string, StringConfig, stringValue]\n\tTimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue]\n\tUintArgs      = ArgumentsBase[uint, IntegerConfig, uintValue[uint]]\n\tUint8Args     = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]]\n\tUint16Args    = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]]\n\tUint32Args    = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]]\n\tUint64Args    = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]]\n)\n\nfunc (c *Command) getArgValue(name string) any {\n\ttracef(\"command %s looking for args %s\", c.Name, name)\n\tfor _, arg := range c.Arguments {\n\t\tif arg.HasName(name) {\n\t\t\ttracef(\"command %s found args %s\", c.Name, name)\n\t\t\treturn arg.Get()\n\t\t}\n\t}\n\ttracef(\"command %s did not find args %s\", c.Name, name)\n\treturn nil\n}\n\nfunc arg[T any](name string, c *Command) T {\n\tval := c.getArgValue(name)\n\tif a, ok := val.(T); ok {\n\t\treturn a\n\t}\n\tvar zero T\n\treturn zero\n}\n\nfunc (c *Command) StringArg(name string) string {\n\treturn arg[string](name, c)\n}\n\nfunc (c *Command) StringArgs(name string) []string {\n\treturn arg[[]string](name, c)\n}\n\nfunc (c *Command) FloatArg(name string) float64 {\n\treturn arg[float64](name, c)\n}\n\nfunc (c *Command) FloatArgs(name string) []float64 {\n\treturn arg[[]float64](name, c)\n}\n\nfunc (c *Command) Float32Arg(name string) float32 {\n\treturn arg[float32](name, c)\n}\n\nfunc (c *Command) Float32Args(name string) []float32 {\n\treturn arg[[]float32](name, c)\n}\n\nfunc (c *Command) Float64Arg(name string) float64 {\n\treturn arg[float64](name, c)\n}\n\nfunc (c *Command) Float64Args(name string) []float64 {\n\treturn arg[[]float64](name, c)\n}\n\nfunc (c *Command) IntArg(name string) int {\n\treturn arg[int](name, c)\n}\n\nfunc (c *Command) IntArgs(name string) []int {\n\treturn arg[[]int](name, c)\n}\n\nfunc (c *Command) Int8Arg(name string) int8 {\n\treturn arg[int8](name, c)\n}\n\nfunc (c *Command) Int8Args(name string) []int8 {\n\treturn arg[[]int8](name, c)\n}\n\nfunc (c *Command) Int16Arg(name string) int16 {\n\treturn arg[int16](name, c)\n}\n\nfunc (c *Command) Int16Args(name string) []int16 {\n\treturn arg[[]int16](name, c)\n}\n\nfunc (c *Command) Int32Arg(name string) int32 {\n\treturn arg[int32](name, c)\n}\n\nfunc (c *Command) Int32Args(name string) []int32 {\n\treturn arg[[]int32](name, c)\n}\n\nfunc (c *Command) Int64Arg(name string) int64 {\n\treturn arg[int64](name, c)\n}\n\nfunc (c *Command) Int64Args(name string) []int64 {\n\treturn arg[[]int64](name, c)\n}\n\nfunc (c *Command) UintArg(name string) uint {\n\treturn arg[uint](name, c)\n}\n\nfunc (c *Command) Uint8Arg(name string) uint8 {\n\treturn arg[uint8](name, c)\n}\n\nfunc (c *Command) Uint16Arg(name string) uint16 {\n\treturn arg[uint16](name, c)\n}\n\nfunc (c *Command) Uint32Arg(name string) uint32 {\n\treturn arg[uint32](name, c)\n}\n\nfunc (c *Command) Uint64Arg(name string) uint64 {\n\treturn arg[uint64](name, c)\n}\n\nfunc (c *Command) UintArgs(name string) []uint {\n\treturn arg[[]uint](name, c)\n}\n\nfunc (c *Command) Uint8Args(name string) []uint8 {\n\treturn arg[[]uint8](name, c)\n}\n\nfunc (c *Command) Uint16Args(name string) []uint16 {\n\treturn arg[[]uint16](name, c)\n}\n\nfunc (c *Command) Uint32Args(name string) []uint32 {\n\treturn arg[[]uint32](name, c)\n}\n\nfunc (c *Command) Uint64Args(name string) []uint64 {\n\treturn arg[[]uint64](name, c)\n}\n\nfunc (c *Command) TimestampArg(name string) time.Time {\n\treturn arg[time.Time](name, c)\n}\n\nfunc (c *Command) TimestampArgs(name string) []time.Time {\n\treturn arg[[]time.Time](name, c)\n}\n"
  },
  {
    "path": "args_test.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestArgNotSet(t *testing.T) {\n\targ := &StringArg{\n\t\tName:  \"sa\",\n\t\tValue: \"foo\",\n\t}\n\n\trequire.Equal(t, \"foo\", arg.Get())\n}\n\nfunc TestArgsMaxNotSet(t *testing.T) {\n\targ := &StringArgs{\n\t\tName:  \"sa\",\n\t\tValue: \"foo\",\n\t}\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.Arguments = []Argument{arg}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\"})\n\trequire.ErrorContains(t, err, \"args sa has max 0, not parsing argument\")\n}\n\nfunc TestArgsMinGtMax(t *testing.T) {\n\targ := &StringArgs{\n\t\tName:  \"sa\",\n\t\tValue: \"foo\",\n\t\tMin:   2,\n\t\tMax:   1,\n\t}\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.Arguments = []Argument{arg}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\"})\n\trequire.ErrorContains(t, err, \"args sa has min[2] > max[1], not parsing argument\")\n}\n\nfunc TestArgsFloatTypes(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tvar fval float64\n\tcmd.Arguments = []Argument{\n\t\t&FloatArg{\n\t\t\tName:        \"ia\",\n\t\t\tDestination: &fval,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"10\"})\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal(float64(10), fval)\n\tr.Equal(float64(10), cmd.FloatArg(\"ia\"))\n\tr.Equal(float64(10), cmd.Float64Arg(\"ia\"))\n\tr.Equal(float32(0), cmd.Float32Arg(\"ia\"))\n\tr.Equal(float64(0), cmd.FloatArg(\"iab\"))\n\tr.Equal(int8(0), cmd.Int8Arg(\"ia\"))\n\tr.Equal(int16(0), cmd.Int16Arg(\"ia\"))\n\tr.Equal(int32(0), cmd.Int32Arg(\"ia\"))\n\tr.Equal(int64(0), cmd.Int64Arg(\"ia\"))\n\tr.Empty(cmd.StringArg(\"ia\"))\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"foo\", \"a\"}))\n}\n\nfunc TestArgsIntTypes(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tvar ival int\n\tcmd.Arguments = []Argument{\n\t\t&IntArg{\n\t\t\tName:        \"ia\",\n\t\t\tDestination: &ival,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"10\"})\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal(10, ival)\n\tr.Equal(10, cmd.IntArg(\"ia\"))\n\tr.Equal(0, cmd.IntArg(\"iab\"))\n\tr.Equal(int8(0), cmd.Int8Arg(\"ia\"))\n\tr.Equal(int16(0), cmd.Int16Arg(\"ia\"))\n\tr.Equal(int32(0), cmd.Int32Arg(\"ia\"))\n\tr.Equal(int64(0), cmd.Int64Arg(\"ia\"))\n\tr.Equal(float64(0), cmd.FloatArg(\"ia\"))\n\tr.Empty(cmd.StringArg(\"ia\"))\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"foo\", \"10.0\"}))\n}\n\nfunc TestArgsFloatSliceTypes(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tvar fval []float64\n\tcmd.Arguments = []Argument{\n\t\t&FloatArgs{\n\t\t\tName:        \"ia\",\n\t\t\tMin:         1,\n\t\t\tMax:         -1,\n\t\t\tDestination: &fval,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"10\", \"20\", \"30\"})\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal([]float64{10, 20, 30}, fval)\n\tr.Equal([]float64{10, 20, 30}, cmd.FloatArgs(\"ia\"))\n\tr.Equal([]float64{10, 20, 30}, cmd.Float64Args(\"ia\"))\n\tr.Nil(cmd.Float32Args(\"ia\"))\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"foo\", \"10\", \"a\"}))\n}\n\nfunc TestArgsIntSliceTypes(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tvar ival []int\n\tcmd.Arguments = []Argument{\n\t\t&IntArgs{\n\t\t\tName:        \"ia\",\n\t\t\tMin:         1,\n\t\t\tMax:         -1,\n\t\t\tDestination: &ival,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"10\", \"20\", \"30\"})\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal([]int{10, 20, 30}, ival)\n\tr.Equal([]int{10, 20, 30}, cmd.IntArgs(\"ia\"))\n\tr.Nil(cmd.Int8Args(\"ia\"))\n\tr.Nil(cmd.Int16Args(\"ia\"))\n\tr.Nil(cmd.Int32Args(\"ia\"))\n\tr.Nil(cmd.Int64Args(\"ia\"))\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"foo\", \"10\", \"20.0\"}))\n}\n\nfunc TestArgsUintTypes(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tvar ival uint\n\tcmd.Arguments = []Argument{\n\t\t&UintArg{\n\t\t\tName:        \"ia\",\n\t\t\tDestination: &ival,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"10\"})\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal(uint(10), ival)\n\tr.Equal(uint(10), cmd.UintArg(\"ia\"))\n\tr.Equal(uint(0), cmd.UintArg(\"iab\"))\n\tr.Equal(uint8(0), cmd.Uint8Arg(\"ia\"))\n\tr.Equal(uint16(0), cmd.Uint16Arg(\"ia\"))\n\tr.Equal(uint32(0), cmd.Uint32Arg(\"ia\"))\n\tr.Equal(uint64(0), cmd.Uint64Arg(\"ia\"))\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"foo\", \"10.0\"}))\n}\n\nfunc TestArgsUintSliceTypes(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tvar ival []uint\n\tcmd.Arguments = []Argument{\n\t\t&UintArgs{\n\t\t\tName:        \"ia\",\n\t\t\tMin:         1,\n\t\t\tMax:         -1,\n\t\t\tDestination: &ival,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"10\", \"20\", \"30\"})\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal([]uint{10, 20, 30}, ival)\n\tr.Equal([]uint{10, 20, 30}, cmd.UintArgs(\"ia\"))\n\tr.Nil(cmd.Uint8Args(\"ia\"))\n\tr.Nil(cmd.Uint16Args(\"ia\"))\n\tr.Nil(cmd.Uint32Args(\"ia\"))\n\tr.Nil(cmd.Uint64Args(\"ia\"))\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"foo\", \"10\", \"20.0\"}))\n}\n\nfunc TestArgumentsRootCommand(t *testing.T) {\n\ttests := []struct {\n\t\tname           string\n\t\targs           []string\n\t\texpectedIvals  []int\n\t\texpectedUivals []uint\n\t\texpectedFvals  []float64\n\t\terrStr         string\n\t}{\n\t\t{\n\t\t\tname:           \"set ival\",\n\t\t\targs:           []string{\"foo\", \"10\"},\n\t\t\texpectedIvals:  []int{10},\n\t\t\texpectedUivals: []uint{},\n\t\t\texpectedFvals:  []float64{},\n\t\t},\n\t\t{\n\t\t\tname:           \"set invalid ival\",\n\t\t\targs:           []string{\"foo\", \"10.0\"},\n\t\t\texpectedIvals:  []int{},\n\t\t\texpectedUivals: []uint{},\n\t\t\texpectedFvals:  []float64{},\n\t\t\terrStr:         \"strconv.ParseInt: parsing \\\"10.0\\\": invalid syntax\",\n\t\t},\n\t\t{\n\t\t\tname:           \"set ival uival\",\n\t\t\targs:           []string{\"foo\", \"-10\", \"11\"},\n\t\t\texpectedIvals:  []int{-10},\n\t\t\texpectedUivals: []uint{11},\n\t\t\texpectedFvals:  []float64{},\n\t\t},\n\t\t{\n\t\t\tname:           \"set ival uival fval\",\n\t\t\targs:           []string{\"foo\", \"-12\", \"14\", \"10.1\"},\n\t\t\texpectedIvals:  []int{-12},\n\t\t\texpectedUivals: []uint{14},\n\t\t\texpectedFvals:  []float64{10.1},\n\t\t},\n\t\t{\n\t\t\tname:           \"set ival uival multu fvals\",\n\t\t\targs:           []string{\"foo\", \"-13\", \"12\", \"10.1\", \"11.09\"},\n\t\t\texpectedIvals:  []int{-13},\n\t\t\texpectedUivals: []uint{12},\n\t\t\texpectedFvals:  []float64{10.1, 11.09},\n\t\t},\n\t\t{\n\t\t\tname:           \"set fvals beyond max\",\n\t\t\targs:           []string{\"foo\", \"13\", \"10\", \"10.1\", \"11.09\", \"12.1\"},\n\t\t\texpectedIvals:  []int{13},\n\t\t\texpectedUivals: []uint{10},\n\t\t\texpectedFvals:  []float64{10.1, 11.09},\n\t\t\terrStr:         \"No help topic for '12.1'\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmd := buildMinimalTestCommand()\n\t\t\tvar ivals []int\n\t\t\tvar uivals []uint\n\t\t\tvar fvals []float64\n\t\t\tcmd.Arguments = []Argument{\n\t\t\t\t&IntArgs{\n\t\t\t\t\tName:        \"ia\",\n\t\t\t\t\tMin:         1,\n\t\t\t\t\tMax:         1,\n\t\t\t\t\tDestination: &ivals,\n\t\t\t\t},\n\t\t\t\t&UintArgs{\n\t\t\t\t\tName:        \"uia\",\n\t\t\t\t\tMin:         1,\n\t\t\t\t\tMax:         1,\n\t\t\t\t\tDestination: &uivals,\n\t\t\t\t},\n\t\t\t\t&FloatArgs{\n\t\t\t\t\tName:        \"fa\",\n\t\t\t\t\tMin:         0,\n\t\t\t\t\tMax:         2,\n\t\t\t\t\tDestination: &fvals,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), test.args)\n\n\t\t\tr := require.New(t)\n\n\t\t\tif test.errStr != \"\" {\n\t\t\t\tr.ErrorContains(err, test.errStr)\n\t\t\t} else {\n\t\t\t\tr.Equal(test.expectedIvals, ivals)\n\t\t\t}\n\t\t\tr.Equal(test.expectedIvals, cmd.IntArgs(\"ia\"))\n\t\t\tr.Equal(test.expectedFvals, cmd.FloatArgs(\"fa\"))\n\t\t\tr.Equal(test.expectedUivals, cmd.UintArgs(\"uia\"))\n\t\t\t/*if test.expectedFvals != nil {\n\t\t\t\tr.Equal(test.expectedFvals, fvals)\n\t\t\t}*/\n\t\t})\n\t}\n}\n\nfunc TestArgumentsInvalidType(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.Arguments = []Argument{\n\t\t&IntArgs{\n\t\t\tName: \"ia\",\n\t\t\tMin:  1,\n\t\t\tMax:  1,\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.Nil(cmd.StringArgs(\"ia\"))\n\tr.Nil(cmd.FloatArgs(\"ia\"))\n\tr.Nil(cmd.Int8Args(\"ia\"))\n\tr.Nil(cmd.Int16Args(\"ia\"))\n\tr.Nil(cmd.Int32Args(\"ia\"))\n\tr.Nil(cmd.Int64Args(\"ia\"))\n\tr.Equal(time.Time{}, cmd.TimestampArg(\"ia\"))\n\tr.Nil(cmd.TimestampArgs(\"ia\"))\n\tr.Nil(cmd.UintArgs(\"ia\"))\n\tr.Nil(cmd.Uint8Args(\"ia\"))\n\tr.Nil(cmd.Uint16Args(\"ia\"))\n\tr.Nil(cmd.Uint32Args(\"ia\"))\n\tr.Nil(cmd.Uint64Args(\"ia\"))\n}\n\nfunc TestArgumentsSubcommand(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\targs          []string\n\t\texpectedIval  int\n\t\texpectedSvals []string\n\t\texpectedTVals []time.Time\n\t\terrStr        string\n\t}{\n\t\t{\n\t\t\tname:   \"insuff args\",\n\t\t\targs:   []string{\"foo\", \"subcmd\", \"2006-01-02T15:04:05Z\"},\n\t\t\terrStr: \"sufficient count of arg sa not provided, given 0 expected 1\",\n\t\t},\n\t\t{\n\t\t\tname:          \"set sval and tval\",\n\t\t\targs:          []string{\"foo\", \"subcmd\", \"2006-01-02T15:04:05Z\", \"fubar\"},\n\t\t\texpectedIval:  10,\n\t\t\texpectedTVals: []time.Time{time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC)},\n\t\t\texpectedSvals: []string{\"fubar\"},\n\t\t},\n\t\t{\n\t\t\tname:          \"set sval, tval and ival\",\n\t\t\targs:          []string{\"foo\", \"subcmd\", \"--foo\", \"100\", \"2006-01-02T15:04:05Z\", \"fubar\", \"some\"},\n\t\t\texpectedIval:  100,\n\t\t\texpectedTVals: []time.Time{time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC)},\n\t\t\texpectedSvals: []string{\"fubar\", \"some\"},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmd := buildMinimalTestCommand()\n\t\t\tvar ival int\n\t\t\tvar svals []string\n\t\t\tvar tvals []time.Time\n\t\t\tcmd.Commands = []*Command{\n\t\t\t\t{\n\t\t\t\t\tName: \"subcmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&IntFlag{\n\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\tValue:       10,\n\t\t\t\t\t\t\tDestination: &ival,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tArguments: []Argument{\n\t\t\t\t\t\t&TimestampArgs{\n\t\t\t\t\t\t\tName:        \"ta\",\n\t\t\t\t\t\t\tMin:         1,\n\t\t\t\t\t\t\tMax:         1,\n\t\t\t\t\t\t\tDestination: &tvals,\n\t\t\t\t\t\t\tConfig: TimestampConfig{\n\t\t\t\t\t\t\t\tLayouts: []string{time.RFC3339},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&StringArgs{\n\t\t\t\t\t\t\tName:        \"sa\",\n\t\t\t\t\t\t\tMin:         1,\n\t\t\t\t\t\t\tMax:         3,\n\t\t\t\t\t\t\tDestination: &svals,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tnumUsageErrors := 0\n\t\t\tcmd.Commands[0].OnUsageError = func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error {\n\t\t\t\tnumUsageErrors++\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), test.args)\n\n\t\t\tr := require.New(t)\n\n\t\t\tif test.errStr != \"\" {\n\t\t\t\tr.ErrorContains(err, test.errStr)\n\t\t\t\tr.Equal(1, numUsageErrors)\n\t\t\t} else {\n\t\t\t\tif test.expectedSvals != nil {\n\t\t\t\t\tr.Equal(test.expectedSvals, svals)\n\t\t\t\t\tr.Equal(test.expectedSvals, cmd.Commands[0].StringArgs(\"sa\"))\n\t\t\t\t}\n\t\t\t\tif test.expectedTVals != nil {\n\t\t\t\t\tr.Equal(test.expectedTVals, tvals)\n\t\t\t\t\tr.Equal(test.expectedTVals, cmd.Commands[0].TimestampArgs(\"ta\"))\n\t\t\t\t}\n\t\t\t\tr.Equal(test.expectedIval, ival)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestArgUsage(t *testing.T) {\n\targ := &IntArg{\n\t\tName: \"ia\",\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\tusage    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"default\",\n\t\t\texpected: \"ia\",\n\t\t},\n\t\t{\n\t\t\tname:     \"usage\",\n\t\t\tusage:    \"foo-usage\",\n\t\t\texpected: \"foo-usage\",\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\targ.UsageText = test.usage\n\t\t\trequire.Equal(t, test.expected, arg.Usage())\n\t\t})\n\t}\n}\n\nfunc TestArgsUsage(t *testing.T) {\n\targ := &IntArgs{\n\t\tName: \"ia\",\n\t\tMin:  0,\n\t\tMax:  1,\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\tmin      int\n\t\tmax      int\n\t\tusage    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"optional\",\n\t\t\tmin:      0,\n\t\t\tmax:      1,\n\t\t\texpected: \"[ia]\",\n\t\t},\n\t\t{\n\t\t\tname:     \"optional\",\n\t\t\tmin:      0,\n\t\t\tmax:      1,\n\t\t\tusage:    \"[my optional usage]\",\n\t\t\texpected: \"[my optional usage]\",\n\t\t},\n\t\t{\n\t\t\tname:     \"zero or more\",\n\t\t\tmin:      0,\n\t\t\tmax:      2,\n\t\t\texpected: \"[ia ...]\",\n\t\t},\n\t\t{\n\t\t\tname:     \"one\",\n\t\t\tmin:      1,\n\t\t\tmax:      1,\n\t\t\texpected: \"ia [ia ...]\",\n\t\t},\n\t\t{\n\t\t\tname:     \"many\",\n\t\t\tmin:      2,\n\t\t\tmax:      1,\n\t\t\texpected: \"ia [ia ...]\",\n\t\t},\n\t\t{\n\t\t\tname:     \"many2\",\n\t\t\tmin:      2,\n\t\t\tmax:      0,\n\t\t\texpected: \"ia [ia ...]\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unlimited\",\n\t\t\tmin:      2,\n\t\t\tmax:      -1,\n\t\t\texpected: \"ia [ia ...]\",\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\targ.Min, arg.Max, arg.UsageText = test.min, test.max, test.usage\n\t\t\trequire.Equal(t, test.expected, arg.Usage())\n\t\t})\n\t}\n}\n\nfunc TestSingleOptionalArg(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\targs     []string\n\t\targValue string\n\t\texp      string\n\t}{\n\t\t{\n\t\t\tname: \"no args\",\n\t\t\targs: []string{\"foo\"},\n\t\t\texp:  \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"no arg with def value\",\n\t\t\targs:     []string{\"foo\"},\n\t\t\targValue: \"bar\",\n\t\t\texp:      \"bar\",\n\t\t},\n\t\t{\n\t\t\tname: \"one arg\",\n\t\t\targs: []string{\"foo\", \"zbar\"},\n\t\t\texp:  \"zbar\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmd := buildMinimalTestCommand()\n\t\t\tvar s1 string\n\t\t\targ := &StringArg{\n\t\t\t\tValue:       test.argValue,\n\t\t\t\tDestination: &s1,\n\t\t\t}\n\t\t\tcmd.Arguments = []Argument{\n\t\t\t\targ,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), test.args) //\n\t\t\tr := require.New(t)\n\t\t\tr.NoError(err)\n\t\t\tr.Equal(test.exp, s1)\n\t\t})\n\t}\n}\n\nfunc TestUnboundedArgs(t *testing.T) {\n\targ := &StringArgs{\n\t\tMin: 0,\n\t\tMax: -1,\n\t}\n\ttests := []struct {\n\t\tname      string\n\t\targs      []string\n\t\tdefValues []string\n\t\tvalues    []string\n\t\texpected  []string\n\t}{\n\t\t{\n\t\t\tname:     \"cmd accepts no args\",\n\t\t\targs:     []string{\"foo\"},\n\t\t\texpected: []string{},\n\t\t},\n\t\t{\n\t\t\tname:     \"cmd uses given args\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"baz\"},\n\t\t\texpected: []string{\"bar\", \"baz\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"cmd uses default values\",\n\t\t\targs:     []string{\"foo\"},\n\t\t\texpected: []string{},\n\t\t},\n\t\t{\n\t\t\tname:     \"given args override default values\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"baz\"},\n\t\t\tvalues:   []string{\"zbar\", \"zbaz\"},\n\t\t\texpected: []string{\"bar\", \"baz\"},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmd := buildMinimalTestCommand()\n\t\t\tcmd.Arguments = []Argument{arg}\n\t\t\targ.Destination = &test.values\n\t\t\trequire.NoError(t, cmd.Run(context.Background(), test.args))\n\t\t\trequire.Equal(t, test.expected, *arg.Destination)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "autocomplete/bash_autocomplete",
    "content": "#!/bin/bash\n\n# This is a shell completion script auto-generated by https://github.com/urfave/cli for bash.\n\n# Macs have bash3 for which the bash-completion package doesn't include\n# _init_completion. This is a minimal version of that function.\n__%[1]s_init_completion() {\n  COMPREPLY=()\n  _get_comp_words_by_ref \"$@\" cur prev words cword\n}\n\n__%[1]s_bash_autocomplete() {\n  if [[ \"${COMP_WORDS[0]}\" != \"source\" ]]; then\n    local cur opts base words\n    COMPREPLY=()\n    cur=\"${COMP_WORDS[COMP_CWORD]}\"\n    if declare -F _init_completion >/dev/null 2>&1; then\n      _init_completion -n \"=:\" || return\n    else\n      __%[1]s_init_completion -n \"=:\" || return\n    fi\n    words=(\"${words[@]:0:$cword}\")\n    if [[ \"$cur\" == \"-\"* ]]; then\n      requestComp=\"${words[*]} ${cur} --generate-shell-completion\"\n    else\n      requestComp=\"${words[*]} --generate-shell-completion\"\n    fi\n    opts=$(eval \"${requestComp}\" 2>/dev/null)\n    COMPREPLY=($(compgen -W \"${opts}\" -- ${cur}))\n    return 0\n  fi\n}\n\ncomplete -o bashdefault -o default -o nospace -F __%[1]s_bash_autocomplete %[1]s\n"
  },
  {
    "path": "autocomplete/fish_autocomplete",
    "content": "# This is a shell completion script auto-generated by https://github.com/urfave/cli for fish.\n\nfunction __%[1]_perform_completion\n    # Extract all args except the last one\n    set -l args (commandline -opc)\n    # Extract the last arg (partial input)\n    set -l lastArg (commandline -ct)\n    \n    set -l results ($args[1] $args[2..-1] $lastArg --generate-shell-completion 2> /dev/null)\n\n    # Remove trailing empty lines\n    for line in $results[-1..1]\n        if test (string trim -- $line) = \"\"\n            set results $results[1..-2]\n        else\n            break\n        end\n    end\n\n    for line in $results\n        if not string match -q -- \"%[1]*\" $line\n            set -l parts (string split -m 1 \":\" -- \"$line\")\n            if test (count $parts) -eq 2\n                printf \"%s\\t%s\\n\" \"$parts[1]\" \"$parts[2]\"\n            else\n                printf \"%s\\n\" \"$line\"\n            end\n        end\n    end\nend\n\n# Clear existing completions for %[1]\ncomplete -c %[1] -e\n# Register completion function\ncomplete -c %[1] -f -a '(__%[1]_perform_completion)'"
  },
  {
    "path": "autocomplete/powershell_autocomplete.ps1",
    "content": "$fn = $($MyInvocation.MyCommand.Name)\n$name = $fn -replace \"(.*)\\.ps1$\", '$1'\nRegister-ArgumentCompleter -Native -CommandName $name -ScriptBlock {\n     param($commandName, $wordToComplete, $cursorPosition)\n     $other = \"$wordToComplete --generate-shell-completion\"\n         Invoke-Expression $other | ForEach-Object {\n            [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n         }\n }\n"
  },
  {
    "path": "autocomplete/zsh_autocomplete",
    "content": "#compdef %[1]s\ncompdef _%[1]s %[1]s\n\n# This is a shell completion script auto-generated by https://github.com/urfave/cli for zsh.\n\n_%[1]s() {\n\tlocal -a opts # Declare a local array\n\tlocal current\n\tcurrent=${words[-1]} # -1 means \"the last element\"\n\tif [[ \"$current\" == \"-\"* ]]; then\n\t\t# Current word starts with a hyphen, so complete flags/options\n\t\topts=(\"${(@f)$(${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}\")\n\telse\n\t\t# Current word does not start with a hyphen, so complete subcommands\n\t\topts=(\"${(@f)$(${words[@]:0:#words[@]-1} --generate-shell-completion)}\")\n\tfi\n\n\tif [[ \"${opts[1]}\" != \"\" ]]; then\n\t\t_describe 'values' opts\n\telse\n\t\t_files\n\tfi\n}\n\n# Don't run the completion function when being source-ed or eval-ed.\n# See https://github.com/urfave/cli/issues/1874 for discussion.\nif [ \"$funcstack[1]\" = \"_%[1]s\" ]; then\n\t_%[1]s\nfi\n"
  },
  {
    "path": "category.go",
    "content": "package cli\n\nimport \"sort\"\n\n// CommandCategories interface allows for category manipulation\ntype CommandCategories interface {\n\t// AddCommand adds a command to a category, creating a new category if necessary.\n\tAddCommand(category string, command *Command)\n\t// Categories returns a slice of categories sorted by name\n\tCategories() []CommandCategory\n}\n\ntype commandCategories []*commandCategory\n\nfunc newCommandCategories() CommandCategories {\n\tret := commandCategories([]*commandCategory{})\n\treturn &ret\n}\n\nfunc (c *commandCategories) Less(i, j int) bool {\n\treturn lexicographicLess((*c)[i].Name(), (*c)[j].Name())\n}\n\nfunc (c *commandCategories) Len() int {\n\treturn len(*c)\n}\n\nfunc (c *commandCategories) Swap(i, j int) {\n\t(*c)[i], (*c)[j] = (*c)[j], (*c)[i]\n}\n\nfunc (c *commandCategories) AddCommand(category string, command *Command) {\n\tfor _, commandCategory := range []*commandCategory(*c) {\n\t\tif commandCategory.name == category {\n\t\t\tcommandCategory.commands = append(commandCategory.commands, command)\n\t\t\treturn\n\t\t}\n\t}\n\tnewVal := append(*c,\n\t\t&commandCategory{name: category, commands: []*Command{command}})\n\t*c = newVal\n}\n\nfunc (c *commandCategories) Categories() []CommandCategory {\n\tret := make([]CommandCategory, len(*c))\n\tfor i, cat := range *c {\n\t\tret[i] = cat\n\t}\n\treturn ret\n}\n\n// CommandCategory is a category containing commands.\ntype CommandCategory interface {\n\t// Name returns the category name string\n\tName() string\n\t// VisibleCommands returns a slice of the Commands with Hidden=false\n\tVisibleCommands() []*Command\n}\n\ntype commandCategory struct {\n\tname     string\n\tcommands []*Command\n}\n\nfunc (c *commandCategory) Name() string {\n\treturn c.name\n}\n\nfunc (c *commandCategory) VisibleCommands() []*Command {\n\tif c.commands == nil {\n\t\tc.commands = []*Command{}\n\t}\n\n\tvar ret []*Command\n\tfor _, command := range c.commands {\n\t\tif !command.Hidden {\n\t\t\tret = append(ret, command)\n\t\t}\n\t}\n\treturn ret\n}\n\n// FlagCategories interface allows for category manipulation\ntype FlagCategories interface {\n\t// AddFlags adds a flag to a category, creating a new category if necessary.\n\tAddFlag(category string, fl Flag)\n\t// VisibleCategories returns a slice of visible flag categories sorted by name\n\tVisibleCategories() []VisibleFlagCategory\n}\n\ntype defaultFlagCategories struct {\n\tm map[string]*defaultVisibleFlagCategory\n}\n\nfunc newFlagCategories() FlagCategories {\n\treturn &defaultFlagCategories{\n\t\tm: map[string]*defaultVisibleFlagCategory{},\n\t}\n}\n\nfunc newFlagCategoriesFromFlags(fs []Flag) FlagCategories {\n\tfc := newFlagCategories()\n\n\tvar categorized bool\n\n\tfor _, fl := range fs {\n\t\tif cf, ok := fl.(CategorizableFlag); ok {\n\t\t\tvisible := false\n\t\t\tif vf, ok := fl.(VisibleFlag); ok {\n\t\t\t\tvisible = vf.IsVisible()\n\t\t\t}\n\t\t\tif cat := cf.GetCategory(); cat != \"\" && visible {\n\t\t\t\tfc.AddFlag(cat, fl)\n\t\t\t\tcategorized = true\n\t\t\t}\n\t\t}\n\t}\n\n\tif categorized {\n\t\tfor _, fl := range fs {\n\t\t\tif cf, ok := fl.(CategorizableFlag); ok {\n\t\t\t\tvisible := false\n\t\t\t\tif vf, ok := fl.(VisibleFlag); ok {\n\t\t\t\t\tvisible = vf.IsVisible()\n\t\t\t\t}\n\t\t\t\tif cf.GetCategory() == \"\" && visible {\n\t\t\t\t\tfc.AddFlag(\"\", fl)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fc\n}\n\nfunc (f *defaultFlagCategories) AddFlag(category string, fl Flag) {\n\tif _, ok := f.m[category]; !ok {\n\t\tf.m[category] = &defaultVisibleFlagCategory{name: category, m: map[string]Flag{}}\n\t}\n\n\tf.m[category].m[fl.String()] = fl\n}\n\nfunc (f *defaultFlagCategories) VisibleCategories() []VisibleFlagCategory {\n\tcatNames := []string{}\n\tfor name := range f.m {\n\t\tcatNames = append(catNames, name)\n\t}\n\n\tsort.Strings(catNames)\n\n\tret := make([]VisibleFlagCategory, len(catNames))\n\tfor i, name := range catNames {\n\t\tret[i] = f.m[name]\n\t}\n\n\treturn ret\n}\n\n// VisibleFlagCategory is a category containing flags.\ntype VisibleFlagCategory interface {\n\t// Name returns the category name string\n\tName() string\n\t// Flags returns a slice of VisibleFlag sorted by name\n\tFlags() []Flag\n}\n\ntype defaultVisibleFlagCategory struct {\n\tname string\n\tm    map[string]Flag\n}\n\nfunc (fc *defaultVisibleFlagCategory) Name() string {\n\treturn fc.name\n}\n\nfunc (fc *defaultVisibleFlagCategory) Flags() []Flag {\n\tvfNames := []string{}\n\tfor flName, fl := range fc.m {\n\t\tif vf, ok := fl.(VisibleFlag); ok {\n\t\t\tif vf.IsVisible() {\n\t\t\t\tvfNames = append(vfNames, flName)\n\t\t\t}\n\t\t}\n\t}\n\n\tsort.Strings(vfNames)\n\n\tret := make([]Flag, len(vfNames))\n\tfor i, flName := range vfNames {\n\t\tret[i] = fc.m[flName]\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "cli.go",
    "content": "// Package cli provides a minimal framework for creating and organizing command line\n// Go applications. cli is designed to be easy to understand and write, the most simple\n// cli application can be written as follows:\n//\n//\tfunc main() {\n//\t\t(&cli.Command{}).Run(context.Background(), os.Args)\n//\t}\n//\n// Of course this application does not do much, so let's make this an actual application:\n//\n//\tfunc main() {\n//\t\tcmd := &cli.Command{\n//\t  \t\tName: \"greet\",\n//\t  \t\tUsage: \"say a greeting\",\n//\t  \t\tAction: func(c *cli.Context) error {\n//\t  \t\t\tfmt.Println(\"Greetings\")\n//\t  \t\t\treturn nil\n//\t  \t\t},\n//\t\t}\n//\n//\t\tcmd.Run(context.Background(), os.Args)\n//\t}\npackage cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nvar isTracingOn = os.Getenv(\"URFAVE_CLI_TRACING\") == \"on\"\n\nfunc tracef(format string, a ...any) {\n\tif !isTracingOn {\n\t\treturn\n\t}\n\n\tif !strings.HasSuffix(format, \"\\n\") {\n\t\tformat = format + \"\\n\"\n\t}\n\n\tpc, file, line, _ := runtime.Caller(1)\n\tcf := runtime.FuncForPC(pc)\n\n\tfmt.Fprintf(\n\t\tos.Stderr,\n\t\tstrings.Join([]string{\n\t\t\t\"## URFAVE CLI TRACE \",\n\t\t\tfile,\n\t\t\t\":\",\n\t\t\tfmt.Sprintf(\"%v\", line),\n\t\t\t\" \",\n\t\t\tfmt.Sprintf(\"(%s)\", cf.Name()),\n\t\t\t\" \",\n\t\t\tformat,\n\t\t}, \"\"),\n\t\ta...,\n\t)\n}\n"
  },
  {
    "path": "cli_test.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc expectFileContent(t *testing.T, file, got string) {\n\tdata, err := os.ReadFile(file)\n\t// Ignore windows line endings\n\tdata = bytes.ReplaceAll(data, []byte(\"\\r\\n\"), []byte(\"\\n\"))\n\n\tr := require.New(t)\n\tr.NoError(err)\n\tr.Equal(got, string(data))\n}\n\nfunc buildTestContext(t *testing.T) context.Context {\n\tctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\n\tt.Cleanup(cancel)\n\n\treturn ctx\n}\n\nfunc TestTracing(t *testing.T) {\n\tolderr := os.Stderr\n\toldtracing := isTracingOn\n\tdefer func() {\n\t\tos.Stderr = olderr\n\t\tisTracingOn = oldtracing\n\t}()\n\n\tfile, err := os.CreateTemp(os.TempDir(), \"cli*\")\n\tassert.NoError(t, err)\n\tos.Stderr = file\n\n\t// Note we cant really set the env since the isTracingOn\n\t// is read at module startup so any changes mid code\n\t// wont take effect\n\tisTracingOn = false\n\ttracef(\"something\")\n\n\tisTracingOn = true\n\ttracef(\"foothing\")\n\n\tassert.NoError(t, file.Close())\n\n\tb, err := os.ReadFile(file.Name())\n\tassert.NoError(t, err)\n\n\tassert.Contains(t, string(b), \"foothing\")\n\tassert.NotContains(t, string(b), \"something\")\n}\n"
  },
  {
    "path": "command.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\t\"strings\"\n)\n\nconst (\n\t// ignoreFlagPrefix is to ignore test flags when adding flags from other packages\n\tignoreFlagPrefix = \"test.\"\n\n\tcommandContextKey = contextKey(\"cli.context\")\n)\n\ntype contextKey string\n\n// Command contains everything needed to run an application that\n// accepts a string slice of arguments such as os.Args. A given\n// Command may contain Flags and sub-commands in Commands.\ntype Command struct {\n\t// The name of the command\n\tName string `json:\"name\"`\n\t// A list of aliases for the command\n\tAliases []string `json:\"aliases\"`\n\t// A short description of the usage of this command\n\tUsage string `json:\"usage\"`\n\t// Text to override the USAGE section of help\n\tUsageText string `json:\"usageText\"`\n\t// A short description of the arguments of this command\n\tArgsUsage string `json:\"argsUsage\"`\n\t// Version of the command\n\tVersion string `json:\"version\"`\n\t// Longer explanation of how the command works\n\tDescription string `json:\"description\"`\n\t// DefaultCommand is the (optional) name of a command\n\t// to run if no command names are passed as CLI arguments.\n\tDefaultCommand string `json:\"defaultCommand\"`\n\t// The category the command is part of\n\tCategory string `json:\"category\"`\n\t// List of child commands\n\tCommands []*Command `json:\"commands\"`\n\t// List of flags to parse\n\tFlags []Flag `json:\"flags\"`\n\t// Boolean to hide built-in help command and help flag\n\tHideHelp bool `json:\"hideHelp\"`\n\t// Ignored if HideHelp is true.\n\tHideHelpCommand bool `json:\"hideHelpCommand\"`\n\t// Boolean to hide built-in version flag and the VERSION section of help\n\tHideVersion bool `json:\"hideVersion\"`\n\t// Boolean to enable shell completion commands\n\tEnableShellCompletion bool `json:\"-\"`\n\t// Shell Completion generation command name\n\tShellCompletionCommandName string `json:\"-\"`\n\t// The function to call when checking for shell command completions\n\tShellComplete ShellCompleteFunc `json:\"-\"`\n\t// The function to configure a shell completion command\n\tConfigureShellCompletionCommand ConfigureShellCompletionCommand `json:\"-\"`\n\t// An action to execute before any subcommands are run, but after the context is ready\n\t// If a non-nil error is returned, no subcommands are run\n\tBefore BeforeFunc `json:\"-\"`\n\t// An action to execute after any subcommands are run, but after the subcommand has finished\n\t// It is run even if Action() panics\n\tAfter AfterFunc `json:\"-\"`\n\t// The function to call when this command is invoked\n\tAction ActionFunc `json:\"-\"`\n\t// Execute this function if the proper command cannot be found\n\tCommandNotFound CommandNotFoundFunc `json:\"-\"`\n\t// Execute this function if a usage error occurs.\n\tOnUsageError OnUsageErrorFunc `json:\"-\"`\n\t// Execute this function when an invalid flag is accessed from the context\n\tInvalidFlagAccessHandler InvalidFlagAccessFunc `json:\"-\"`\n\t// Boolean to hide this command from help or completion\n\tHidden bool `json:\"hidden\"`\n\t// List of all authors who contributed (string or fmt.Stringer)\n\t// TODO: ~string | fmt.Stringer when interface unions are available\n\tAuthors []any `json:\"authors\"`\n\t// Copyright of the binary if any\n\tCopyright string `json:\"copyright\"`\n\t// Reader reader to write input to (useful for tests)\n\tReader io.Reader `json:\"-\"`\n\t// Writer writer to write output to\n\tWriter io.Writer `json:\"-\"`\n\t// ErrWriter writes error output\n\tErrWriter io.Writer `json:\"-\"`\n\t// ExitErrHandler processes any error encountered while running a Command before it is\n\t// returned to the caller. If no function is provided, HandleExitCoder is used as the\n\t// default behavior.\n\tExitErrHandler ExitErrHandlerFunc `json:\"-\"`\n\t// Other custom info\n\tMetadata map[string]interface{} `json:\"metadata\"`\n\t// Carries a function which returns app specific info.\n\tExtraInfo func() map[string]string `json:\"-\"`\n\t// CustomRootCommandHelpTemplate the text template for app help topic.\n\t// cli.go uses text/template to render templates. You can\n\t// render custom help text by setting this variable.\n\tCustomRootCommandHelpTemplate string `json:\"-\"`\n\t// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is \",\"\n\tSliceFlagSeparator string `json:\"sliceFlagSeparator\"`\n\t// DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false\n\tDisableSliceFlagSeparator bool `json:\"disableSliceFlagSeparator\"`\n\t// MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is \"=\"\n\tMapFlagKeyValueSeparator string `json:\"mapFlagKeyValueSeparator\"`\n\t// Boolean to enable short-option handling so user can combine several\n\t// single-character bool arguments into one\n\t// i.e. foobar -o -v -> foobar -ov\n\tUseShortOptionHandling bool `json:\"useShortOptionHandling\"`\n\t// Enable suggestions for commands and flags\n\tSuggest bool `json:\"suggest\"`\n\t// Allows global flags set by libraries which use flag.XXXVar(...) directly\n\t// to be parsed through this library\n\tAllowExtFlags bool `json:\"allowExtFlags\"`\n\t// Treat all flags as normal arguments if true\n\tSkipFlagParsing bool `json:\"skipFlagParsing\"`\n\t// CustomHelpTemplate the text template for the command help topic.\n\t// cli.go uses text/template to render templates. You can\n\t// render custom help text by setting this variable.\n\tCustomHelpTemplate string `json:\"-\"`\n\t// Use longest prefix match for commands\n\tPrefixMatchCommands bool `json:\"prefixMatchCommands\"`\n\t// Custom suggest command for matching\n\tSuggestCommandFunc SuggestCommandFunc `json:\"-\"`\n\t// Flag exclusion group\n\tMutuallyExclusiveFlags []MutuallyExclusiveFlags `json:\"mutuallyExclusiveFlags\"`\n\t// Arguments to parse for this command\n\tArguments []Argument `json:\"arguments\"`\n\t// Whether to read arguments from stdin\n\t// applicable to root command only\n\tReadArgsFromStdin bool `json:\"readArgsFromStdin\"`\n\t// StopOnNthArg provides v2-like behavior for specific commands by stopping\n\t// flag parsing after N positional arguments are encountered. When set to N,\n\t// all remaining arguments after the Nth positional argument will be treated\n\t// as arguments, not flags.\n\t//\n\t// A value of 0 means all arguments are treated as positional (no flag parsing).\n\t// A nil value means normal v3 flag parsing behavior (flags can appear anywhere).\n\tStopOnNthArg *int `json:\"stopOnNthArg\"`\n\n\t// categories contains the categorized commands and is populated on app startup\n\tcategories CommandCategories\n\t// flagCategories contains the categorized flags and is populated on app startup\n\tflagCategories FlagCategories\n\t// flags that have been applied in current parse\n\tappliedFlags []Flag\n\t// flags that have been set\n\tsetFlags map[Flag]struct{}\n\t// The parent of this command. This value will be nil for the\n\t// command at the root of the graph.\n\tparent *Command\n\t// parsed args\n\tparsedArgs Args\n\t// track state of error handling\n\tisInError bool\n\t// track state of defaults\n\tdidSetupDefaults bool\n\t// whether in shell completion mode\n\tshellCompletion bool\n\t// whether global help flag was added\n\tglobaHelpFlagAdded bool\n\t// whether global version flag was added\n\tglobaVersionFlagAdded bool\n\t// whether this is a completion command\n\tisCompletionCommand bool\n}\n\n// FullName returns the full name of the command.\n// For commands with parents this ensures that the parent commands\n// are part of the command path.\nfunc (cmd *Command) FullName() string {\n\tnamePath := []string{}\n\n\tif cmd.parent != nil {\n\t\tnamePath = append(namePath, cmd.parent.FullName())\n\t}\n\n\treturn strings.Join(append(namePath, cmd.Name), \" \")\n}\n\nfunc (cmd *Command) Command(name string) *Command {\n\tfor _, subCmd := range cmd.Commands {\n\t\tif subCmd.HasName(name) {\n\t\t\treturn subCmd\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (cmd *Command) checkHelp() bool {\n\ttracef(\"checking if help is wanted (cmd=%[1]q)\", cmd.Name)\n\n\treturn HelpFlag != nil && slices.ContainsFunc(HelpFlag.Names(), cmd.Bool)\n}\n\nfunc (cmd *Command) allFlags() []Flag {\n\tvar flags []Flag\n\tflags = append(flags, cmd.Flags...)\n\tfor _, grpf := range cmd.MutuallyExclusiveFlags {\n\t\tfor _, f1 := range grpf.Flags {\n\t\t\tflags = append(flags, f1...)\n\t\t}\n\t}\n\treturn flags\n}\n\n// useShortOptionHandling traverses Lineage() for *any* ancestors\n// with UseShortOptionHandling\nfunc (cmd *Command) useShortOptionHandling() bool {\n\tfor _, pCmd := range cmd.Lineage() {\n\t\tif pCmd.UseShortOptionHandling {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (cmd *Command) suggestFlagFromError(err error, commandName string) (string, error) {\n\tfl, parseErr := flagFromError(err)\n\tif parseErr != nil {\n\t\treturn \"\", err\n\t}\n\n\tflags := cmd.Flags\n\thideHelp := cmd.hideHelp()\n\n\tif commandName != \"\" {\n\t\tsubCmd := cmd.Command(commandName)\n\t\tif subCmd == nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tflags = subCmd.Flags\n\t\thideHelp = hideHelp || subCmd.HideHelp\n\t}\n\n\tsuggestion := SuggestFlag(flags, fl, hideHelp)\n\tif len(suggestion) == 0 {\n\t\treturn \"\", err\n\t}\n\n\treturn fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion) + \"\\n\\n\", nil\n}\n\n// Names returns the names including short names and aliases.\nfunc (cmd *Command) Names() []string {\n\treturn append([]string{cmd.Name}, cmd.Aliases...)\n}\n\n// HasName returns true if Command.Name matches given name\nfunc (cmd *Command) HasName(name string) bool {\n\treturn slices.Contains(cmd.Names(), name)\n}\n\n// VisibleCategories returns a slice of categories and commands that are\n// Hidden=false\nfunc (cmd *Command) VisibleCategories() []CommandCategory {\n\tret := []CommandCategory{}\n\tfor _, category := range cmd.categories.Categories() {\n\t\tif visible := func() CommandCategory {\n\t\t\tif len(category.VisibleCommands()) > 0 {\n\t\t\t\treturn category\n\t\t\t}\n\t\t\treturn nil\n\t\t}(); visible != nil {\n\t\t\tret = append(ret, visible)\n\t\t}\n\t}\n\treturn ret\n}\n\n// VisibleCommands returns a slice of the Commands with Hidden=false\nfunc (cmd *Command) VisibleCommands() []*Command {\n\tvar ret []*Command\n\tfor _, command := range cmd.Commands {\n\t\tif command.Hidden || command.Name == helpName {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, command)\n\t}\n\treturn ret\n}\n\n// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain\nfunc (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory {\n\tif cmd.flagCategories == nil {\n\t\tcmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())\n\t}\n\treturn cmd.flagCategories.VisibleCategories()\n}\n\n// VisibleFlags returns a slice of the Flags with Hidden=false\nfunc (cmd *Command) VisibleFlags() []Flag {\n\treturn visibleFlags(cmd.allFlags())\n}\n\nfunc (cmd *Command) appendFlag(fl Flag) {\n\tif !hasFlag(cmd.Flags, fl) {\n\t\tcmd.Flags = append(cmd.Flags, fl)\n\t}\n}\n\n// VisiblePersistentFlags returns a slice of [LocalFlag] with Persistent=true and Hidden=false.\nfunc (cmd *Command) VisiblePersistentFlags() []Flag {\n\tvar flags []Flag\n\tfor _, fl := range cmd.Root().Flags {\n\t\tpfl, ok := fl.(LocalFlag)\n\t\tif !ok || pfl.IsLocal() {\n\t\t\tcontinue\n\t\t}\n\t\tflags = append(flags, fl)\n\t}\n\treturn visibleFlags(flags)\n}\n\nfunc (cmd *Command) appendCommand(aCmd *Command) {\n\tif !slices.Contains(cmd.Commands, aCmd) {\n\t\taCmd.parent = cmd\n\t\tcmd.Commands = append(cmd.Commands, aCmd)\n\t}\n}\n\nfunc (cmd *Command) handleExitCoder(ctx context.Context, err error) error {\n\tif cmd.parent != nil {\n\t\treturn cmd.parent.handleExitCoder(ctx, err)\n\t}\n\n\tif cmd.ExitErrHandler != nil {\n\t\tcmd.ExitErrHandler(ctx, cmd, err)\n\t\treturn err\n\t}\n\n\tHandleExitCoder(err)\n\treturn err\n}\n\nfunc (cmd *Command) argsWithDefaultCommand(oldArgs Args) Args {\n\trawArgs := append([]string{cmd.DefaultCommand}, oldArgs.Slice()...)\n\tnewArgs := &stringSliceArgs{v: rawArgs}\n\n\treturn newArgs\n}\n\n// Root returns the Command at the root of the graph\nfunc (cmd *Command) Root() *Command {\n\tif cmd.parent == nil {\n\t\treturn cmd\n\t}\n\n\treturn cmd.parent.Root()\n}\n\nfunc (cmd *Command) set(fName string, f Flag, val string) error {\n\tcmd.setFlags[f] = struct{}{}\n\tcmd.setMultiValueParsingConfig(f)\n\tif err := f.Set(fName, val); err != nil {\n\t\treturn fmt.Errorf(\"invalid value %q for flag -%s: %v\", val, fName, err)\n\t}\n\treturn nil\n}\n\nfunc (cmd *Command) lFlag(name string) Flag {\n\tfor _, f := range cmd.allFlags() {\n\t\tif slices.Contains(f.Names(), name) {\n\t\t\ttracef(\"flag found for name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\t\t\treturn f\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (cmd *Command) lookupFlag(name string) Flag {\n\tfor _, pCmd := range cmd.Lineage() {\n\t\tif f := pCmd.lFlag(name); f != nil {\n\t\t\treturn f\n\t\t}\n\t}\n\n\ttracef(\"flag NOT found for name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\tcmd.onInvalidFlag(context.TODO(), name)\n\treturn nil\n}\n\n// this looks up only allowed flags, i.e. local flags for current command\n// or persistent flags from ancestors\nfunc (cmd *Command) lookupAppliedFlag(name string) Flag {\n\tfor _, f := range cmd.appliedFlags {\n\t\tif slices.Contains(f.Names(), name) {\n\t\t\ttracef(\"appliedFlag found for name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\t\t\treturn f\n\t\t}\n\t}\n\n\ttracef(\"lookupAppliedflag NOT found for name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\tcmd.onInvalidFlag(context.TODO(), name)\n\treturn nil\n}\n\nfunc (cmd *Command) checkRequiredFlag(f Flag) (bool, string) {\n\tif rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {\n\t\tflagName := f.Names()[0]\n\t\tif !f.IsSet() {\n\t\t\treturn false, flagName\n\t\t}\n\t}\n\treturn true, \"\"\n}\n\nfunc (cmd *Command) checkAllRequiredFlags() requiredFlagsErr {\n\tfor pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {\n\t\tif err := pCmd.checkRequiredFlags(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (cmd *Command) checkRequiredFlags() requiredFlagsErr {\n\ttracef(\"checking for required flags (cmd=%[1]q)\", cmd.Name)\n\n\tmissingFlags := []string{}\n\n\tfor _, f := range cmd.appliedFlags {\n\t\tif ok, name := cmd.checkRequiredFlag(f); !ok {\n\t\t\tmissingFlags = append(missingFlags, name)\n\t\t}\n\t}\n\n\tif len(missingFlags) != 0 {\n\t\ttracef(\"found missing required flags %[1]q (cmd=%[2]q)\", missingFlags, cmd.Name)\n\n\t\treturn &errRequiredFlags{missingFlags: missingFlags}\n\t}\n\n\ttracef(\"all required flags set (cmd=%[1]q)\", cmd.Name)\n\n\treturn nil\n}\n\nfunc (cmd *Command) onInvalidFlag(ctx context.Context, name string) {\n\tfor cmd != nil {\n\t\tif cmd.InvalidFlagAccessHandler != nil {\n\t\t\tcmd.InvalidFlagAccessHandler(ctx, cmd, name)\n\t\t\tbreak\n\t\t}\n\t\tcmd = cmd.parent\n\t}\n}\n\n// NumFlags returns the number of flags set\nfunc (cmd *Command) NumFlags() int {\n\ttracef(\"numFlags numAppliedFlags %d\", len(cmd.appliedFlags))\n\tcount := 0\n\tfor _, f := range cmd.appliedFlags {\n\t\tif f.IsSet() {\n\t\t\tcount++\n\t\t}\n\t}\n\treturn count // cmd.flagSet.NFlag()\n}\n\nfunc (cmd *Command) setMultiValueParsingConfig(f Flag) {\n\ttracef(\"setMultiValueParsingConfig %T, %+v\", f, f)\n\tif cf, ok := f.(multiValueParsingConfigSetter); ok {\n\t\tcf.setMultiValueParsingConfig(multiValueParsingConfig{\n\t\t\tSliceFlagSeparator:        cmd.SliceFlagSeparator,\n\t\t\tDisableSliceFlagSeparator: cmd.DisableSliceFlagSeparator,\n\t\t\tMapFlagKeyValueSeparator:  cmd.MapFlagKeyValueSeparator,\n\t\t})\n\t}\n}\n\n// Set sets a context flag to a value.\nfunc (cmd *Command) Set(name, value string) error {\n\tif f := cmd.lookupFlag(name); f != nil {\n\t\tcmd.setMultiValueParsingConfig(f)\n\t\treturn f.Set(name, value)\n\t}\n\n\treturn fmt.Errorf(\"no such flag -%s\", name)\n}\n\n// IsSet determines if the flag was actually set\nfunc (cmd *Command) IsSet(name string) bool {\n\tfl := cmd.lookupFlag(name)\n\tif fl == nil {\n\t\ttracef(\"flag with name %[1]q NOT found; assuming not set (cmd=%[2]q)\", name, cmd.Name)\n\t\treturn false\n\t}\n\n\tisSet := fl.IsSet()\n\tif isSet {\n\t\ttracef(\"flag with name %[1]q is set (cmd=%[2]q)\", name, cmd.Name)\n\t} else {\n\t\ttracef(\"flag with name %[1]q is no set (cmd=%[2]q)\", name, cmd.Name)\n\t}\n\n\treturn isSet\n}\n\n// LocalFlagNames returns a slice of flag names used in this\n// command.\nfunc (cmd *Command) LocalFlagNames() []string {\n\tnames := []string{}\n\n\t// Check the flags which have been set via env or file\n\tfor _, f := range cmd.allFlags() {\n\t\tif f.IsSet() {\n\t\t\tnames = append(names, f.Names()...)\n\t\t}\n\t}\n\n\t// Sort out the duplicates since flag could be set via multiple\n\t// paths\n\tm := map[string]struct{}{}\n\tuniqNames := []string{}\n\n\tfor _, name := range names {\n\t\tif _, ok := m[name]; !ok {\n\t\t\tm[name] = struct{}{}\n\t\t\tuniqNames = append(uniqNames, name)\n\t\t}\n\t}\n\n\treturn uniqNames\n}\n\n// FlagNames returns a slice of flag names used by the this command\n// and all of its parent commands.\nfunc (cmd *Command) FlagNames() []string {\n\tnames := cmd.LocalFlagNames()\n\n\tif cmd.parent != nil {\n\t\tnames = append(cmd.parent.FlagNames(), names...)\n\t}\n\n\treturn names\n}\n\n// Lineage returns *this* command and all of its ancestor commands\n// in order from child to parent\nfunc (cmd *Command) Lineage() []*Command {\n\tlineage := []*Command{cmd}\n\n\tif cmd.parent != nil {\n\t\tlineage = append(lineage, cmd.parent.Lineage()...)\n\t}\n\n\treturn lineage\n}\n\n// Count returns the num of occurrences of this flag\nfunc (cmd *Command) Count(name string) int {\n\tif cf, ok := cmd.lookupFlag(name).(Countable); ok {\n\t\treturn cf.Count()\n\t}\n\treturn 0\n}\n\n// Value returns the value of the flag corresponding to `name`\nfunc (cmd *Command) Value(name string) interface{} {\n\tif fs := cmd.lookupFlag(name); fs != nil {\n\t\ttracef(\"value found for name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\t\treturn fs.Get()\n\t}\n\n\ttracef(\"value NOT found for name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn nil\n}\n\n// Args returns the command line arguments associated with the\n// command.\nfunc (cmd *Command) Args() Args {\n\treturn cmd.parsedArgs\n}\n\n// NArg returns the number of the command line arguments.\nfunc (cmd *Command) NArg() int {\n\treturn cmd.Args().Len()\n}\n\nfunc (cmd *Command) runFlagActions(ctx context.Context) error {\n\ttracef(\"runFlagActions\")\n\tfor fl := range cmd.setFlags {\n\t\t/*tracef(\"checking %v:%v\", fl.Names(), fl.IsSet())\n\t\tif !fl.IsSet() {\n\t\t\tcontinue\n\t\t}*/\n\n\t\t//if pf, ok := fl.(LocalFlag); ok && !pf.IsLocal() {\n\t\t//\tcontinue\n\t\t//}\n\n\t\tif af, ok := fl.(ActionableFlag); ok {\n\t\t\tif err := af.RunAction(ctx, cmd); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "command_parse.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"unicode\"\n)\n\nconst (\n\tprovidedButNotDefinedErrMsg = \"flag provided but not defined: -\"\n\targumentNotProvidedErrMsg   = \"flag needs an argument: \"\n)\n\n// flagFromError tries to parse a provided flag from an error message. If the\n// parsing fails, it returns the input error and an empty string\nfunc flagFromError(err error) (string, error) {\n\terrStr := err.Error()\n\ttrimmed := strings.TrimPrefix(errStr, providedButNotDefinedErrMsg)\n\tif errStr == trimmed {\n\t\treturn \"\", err\n\t}\n\treturn trimmed, nil\n}\n\nfunc (cmd *Command) parseFlags(args Args) (Args, error) {\n\ttracef(\"parsing flags from arguments %[1]q (cmd=%[2]q)\", args, cmd.Name)\n\n\tcmd.setFlags = map[Flag]struct{}{}\n\tcmd.appliedFlags = cmd.allFlags()\n\n\ttracef(\"walking command lineage for persistent flags (cmd=%[1]q)\", cmd.Name)\n\n\tfor pCmd := cmd.parent; pCmd != nil; pCmd = pCmd.parent {\n\t\ttracef(\n\t\t\t\"checking ancestor command=%[1]q for persistent flags (cmd=%[2]q)\",\n\t\t\tpCmd.Name, cmd.Name,\n\t\t)\n\n\t\tfor _, fl := range pCmd.allFlags() {\n\t\t\tflNames := fl.Names()\n\n\t\t\tpfl, ok := fl.(LocalFlag)\n\t\t\tif !ok || pfl.IsLocal() {\n\t\t\t\ttracef(\"skipping non-persistent flag %[1]q (cmd=%[2]q)\", flNames, cmd.Name)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttracef(\n\t\t\t\t\"checking for applying persistent flag=%[1]q pCmd=%[2]q (cmd=%[3]q)\",\n\t\t\t\tflNames, pCmd.Name, cmd.Name,\n\t\t\t)\n\n\t\t\tapplyPersistentFlag := true\n\n\t\t\tfor _, name := range flNames {\n\t\t\t\tif cmd.lFlag(name) != nil {\n\t\t\t\t\tapplyPersistentFlag = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !applyPersistentFlag {\n\t\t\t\ttracef(\"not applying as persistent flag=%[1]q (cmd=%[2]q)\", flNames, cmd.Name)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttracef(\"applying as persistent flag=%[1]q (cmd=%[2]q)\", flNames, cmd.Name)\n\n\t\t\ttracef(\"appending to applied flags flag=%[1]q (cmd=%[2]q)\", flNames, cmd.Name)\n\t\t\tcmd.appliedFlags = append(cmd.appliedFlags, fl)\n\t\t}\n\t}\n\n\ttracef(\"parsing flags iteratively tail=%[1]q (cmd=%[2]q)\", args.Tail(), cmd.Name)\n\tdefer tracef(\"done parsing flags (cmd=%[1]q)\", cmd.Name)\n\n\tposArgs := []string{}\n\tfor rargs := args.Slice(); len(rargs) > 0; rargs = rargs[1:] {\n\t\ttracef(\"rearrange:1 (cmd=%[1]q) %[2]q\", cmd.Name, rargs)\n\n\t\tfirstArg := strings.TrimSpace(rargs[0])\n\t\tif len(firstArg) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\t// stop parsing once we see a \"--\"\n\t\tif firstArg == \"--\" {\n\t\t\tposArgs = append(posArgs, rargs[1:]...)\n\t\t\treturn &stringSliceArgs{posArgs}, nil\n\t\t}\n\n\t\t// Check if we've reached the Nth argument and should stop flag parsing\n\t\tif cmd.StopOnNthArg != nil && len(posArgs) == *cmd.StopOnNthArg {\n\t\t\t// Append current arg and all remaining args without parsing\n\t\t\tposArgs = append(posArgs, rargs[0:]...)\n\t\t\treturn &stringSliceArgs{posArgs}, nil\n\t\t}\n\n\t\t// handle positional args\n\t\tif firstArg[0] != '-' {\n\t\t\t// positional argument probably\n\t\t\ttracef(\"rearrange-3 (cmd=%[1]q) check %[2]q\", cmd.Name, firstArg)\n\n\t\t\t// if there is a command by that name let the command handle the\n\t\t\t// rest of the parsing\n\t\t\tif cmd.Command(firstArg) != nil {\n\t\t\t\tposArgs = append(posArgs, rargs...)\n\t\t\t\treturn &stringSliceArgs{posArgs}, nil\n\t\t\t}\n\n\t\t\tposArgs = append(posArgs, firstArg)\n\t\t\tcontinue\n\t\t}\n\n\t\tnumMinuses := 1\n\t\t// this is same as firstArg == \"-\"\n\t\tif len(firstArg) == 1 {\n\t\t\tposArgs = append(posArgs, firstArg)\n\t\t\tbreak\n\t\t}\n\n\t\tshortOptionHandling := cmd.useShortOptionHandling()\n\n\t\t// stop parsing -- as short flags\n\t\tif firstArg[1] == '-' {\n\t\t\tnumMinuses++\n\t\t\tshortOptionHandling = false\n\t\t} else if !unicode.IsLetter(rune(firstArg[1])) {\n\t\t\t// this is not a flag\n\t\t\ttracef(\"parseFlags not a unicode letter. Stop parsing\")\n\t\t\tposArgs = append(posArgs, rargs...)\n\t\t\treturn &stringSliceArgs{posArgs}, nil\n\t\t}\n\n\t\ttracef(\"parseFlags (shortOptionHandling=%[1]q)\", shortOptionHandling)\n\n\t\tflagName := firstArg[numMinuses:]\n\t\tflagVal := \"\"\n\t\tvalFromEqual := false\n\t\ttracef(\"flagName:1 (fName=%[1]q)\", flagName)\n\t\tif index := strings.Index(flagName, \"=\"); index != -1 {\n\t\t\tflagVal = flagName[index+1:]\n\t\t\tflagName = flagName[:index]\n\t\t\tvalFromEqual = true\n\t\t}\n\n\t\ttracef(\"flagName:2 (fName=%[1]q) (fVal=%[2]q)\", flagName, flagVal)\n\n\t\tf := cmd.lookupAppliedFlag(flagName)\n\t\t// found a flag matching given flagName\n\t\tif f != nil {\n\t\t\ttracef(\"Trying flag type (fName=%[1]q) (type=%[2]T)\", flagName, f)\n\t\t\tif fb, ok := f.(boolFlag); ok && fb.IsBoolFlag() {\n\t\t\t\tif flagVal == \"\" {\n\t\t\t\t\tflagVal = \"true\"\n\t\t\t\t}\n\t\t\t\ttracef(\"parse Apply bool flag (fName=%[1]q) (fVal=%[2]q)\", flagName, flagVal)\n\t\t\t\tif err := cmd.set(flagName, f, flagVal); err != nil {\n\t\t\t\t\treturn &stringSliceArgs{posArgs}, err\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttracef(\"processing non bool flag (fName=%[1]q)\", flagName)\n\t\t\t// not a bool flag so need to get the next arg\n\t\t\tif flagVal == \"\" {\n\t\t\t\tif len(rargs) == 1 || valFromEqual {\n\t\t\t\t\treturn &stringSliceArgs{posArgs}, fmt.Errorf(\"%s%s\", argumentNotProvidedErrMsg, firstArg)\n\t\t\t\t}\n\t\t\t\tflagVal = rargs[1]\n\t\t\t\trargs = rargs[1:]\n\t\t\t}\n\n\t\t\ttracef(\"setting non bool flag (fName=%[1]q) (fVal=%[2]q)\", flagName, flagVal)\n\t\t\tif err := cmd.set(flagName, f, flagVal); err != nil {\n\t\t\t\treturn &stringSliceArgs{posArgs}, err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// no flag lookup found and short handling is disabled\n\t\tif !shortOptionHandling {\n\t\t\treturn &stringSliceArgs{posArgs}, fmt.Errorf(\"%s%s\", providedButNotDefinedErrMsg, flagName)\n\t\t}\n\n\t\t// try to split the flags\n\t\tfor index, c := range flagName {\n\t\t\ttracef(\"processing flag (fName=%[1]q)\", string(c))\n\t\t\tif sf := cmd.lookupFlag(string(c)); sf == nil {\n\t\t\t\treturn &stringSliceArgs{posArgs}, fmt.Errorf(\"%s%s\", providedButNotDefinedErrMsg, flagName)\n\t\t\t} else if fb, ok := sf.(boolFlag); ok && fb.IsBoolFlag() {\n\t\t\t\tfv := flagVal\n\t\t\t\tif index == (len(flagName)-1) && flagVal == \"\" {\n\t\t\t\t\tfv = \"true\"\n\t\t\t\t}\n\t\t\t\tif fv == \"\" {\n\t\t\t\t\tfv = \"true\"\n\t\t\t\t}\n\t\t\t\tif err := cmd.set(flagName, sf, fv); err != nil {\n\t\t\t\t\ttracef(\"processing flag.2 (fName=%[1]q)\", string(c))\n\t\t\t\t\treturn &stringSliceArgs{posArgs}, err\n\t\t\t\t}\n\t\t\t} else if index == len(flagName)-1 { // last flag can take an arg\n\t\t\t\tif flagVal == \"\" {\n\t\t\t\t\tif len(rargs) == 1 {\n\t\t\t\t\t\treturn &stringSliceArgs{posArgs}, fmt.Errorf(\"%s%s\", argumentNotProvidedErrMsg, string(c))\n\t\t\t\t\t}\n\t\t\t\t\tflagVal = rargs[1]\n\t\t\t\t\trargs = rargs[1:]\n\t\t\t\t}\n\t\t\t\ttracef(\"parseFlags (flagName %[1]q) (flagVal %[2]q)\", flagName, flagVal)\n\t\t\t\tif err := cmd.set(flagName, sf, flagVal); err != nil {\n\t\t\t\t\ttracef(\"processing flag.4 (fName=%[1]q)\", string(c))\n\t\t\t\t\treturn &stringSliceArgs{posArgs}, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ttracef(\"returning-2 (cmd=%[1]q) args %[2]q\", cmd.Name, posArgs)\n\treturn &stringSliceArgs{posArgs}, nil\n}\n"
  },
  {
    "path": "command_run.go",
    "content": "package cli\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\t\"unicode\"\n)\n\nfunc (cmd *Command) parseArgsFromStdin() ([]string, error) {\n\ttype state int\n\tconst (\n\t\tstateSearchForToken  state = -1\n\t\tstateSearchForString state = 0\n\t)\n\n\tst := stateSearchForToken\n\tlinenum := 1\n\ttoken := \"\"\n\targs := []string{}\n\n\tbreader := bufio.NewReader(cmd.Reader)\n\nouter:\n\tfor {\n\t\tch, _, err := breader.ReadRune()\n\t\tif err == io.EOF {\n\t\t\tswitch st {\n\t\t\tcase stateSearchForToken:\n\t\t\t\tif token != \"--\" {\n\t\t\t\t\targs = append(args, token)\n\t\t\t\t}\n\t\t\tcase stateSearchForString:\n\t\t\t\t// make sure string is not empty\n\t\t\t\tfor _, t := range token {\n\t\t\t\t\tif !unicode.IsSpace(t) {\n\t\t\t\t\t\targs = append(args, token)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak outer\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tswitch st {\n\t\tcase stateSearchForToken:\n\t\t\tif unicode.IsSpace(ch) || ch == '\"' {\n\t\t\t\tif ch == '\\n' {\n\t\t\t\t\tlinenum++\n\t\t\t\t}\n\t\t\t\tif token != \"\" {\n\t\t\t\t\t// end the processing here\n\t\t\t\t\tif token == \"--\" {\n\t\t\t\t\t\tbreak outer\n\t\t\t\t\t}\n\t\t\t\t\targs = append(args, token)\n\t\t\t\t\ttoken = \"\"\n\t\t\t\t}\n\t\t\t\tif ch == '\"' {\n\t\t\t\t\tst = stateSearchForString\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttoken += string(ch)\n\t\tcase stateSearchForString:\n\t\t\tif ch != '\"' {\n\t\t\t\ttoken += string(ch)\n\t\t\t} else {\n\t\t\t\tif token != \"\" {\n\t\t\t\t\targs = append(args, token)\n\t\t\t\t\ttoken = \"\"\n\t\t\t\t}\n\t\t\t\t/*else {\n\t\t\t\t\t//TODO. Should we pass in empty strings ?\n\t\t\t\t}*/\n\t\t\t\tst = stateSearchForToken\n\t\t\t}\n\t\t}\n\t}\n\n\ttracef(\"parsed stdin args as %v (cmd=%[2]q)\", args, cmd.Name)\n\n\treturn args, nil\n}\n\n// Run is the entry point to the command graph. The positional\n// arguments are parsed according to the Flag and Command\n// definitions and the matching Action functions are run.\nfunc (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) {\n\t_, deferErr = cmd.run(ctx, osArgs)\n\treturn deferErr\n}\n\nfunc (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context, deferErr error) {\n\ttracef(\"running with arguments %[1]q (cmd=%[2]q)\", osArgs, cmd.Name)\n\tcmd.setupDefaults(osArgs)\n\n\t// Validate StopOnNthArg\n\tif cmd.StopOnNthArg != nil && *cmd.StopOnNthArg < 0 {\n\t\treturn ctx, fmt.Errorf(\"StopOnNthArg must be non-negative, got %d\", *cmd.StopOnNthArg)\n\t}\n\n\tif v, ok := ctx.Value(commandContextKey).(*Command); ok {\n\t\ttracef(\"setting parent (cmd=%[1]q) command from context.Context value (cmd=%[2]q)\", v.Name, cmd.Name)\n\t\tcmd.parent = v\n\t}\n\n\tif cmd.parent == nil {\n\t\tif cmd.ReadArgsFromStdin {\n\t\t\tif args, err := cmd.parseArgsFromStdin(); err != nil {\n\t\t\t\treturn ctx, err\n\t\t\t} else {\n\t\t\t\tosArgs = append(osArgs, args...)\n\t\t\t}\n\t\t}\n\t\t// handle the completion flag separately from the flagset since\n\t\t// completion could be attempted after a flag, but before its value was put\n\t\t// on the command line. this causes the flagset to interpret the completion\n\t\t// flag name as the value of the flag before it which is undesirable\n\t\t// note that we can only do this because the shell autocomplete function\n\t\t// always appends the completion flag at the end of the command\n\t\ttracef(\"checking osArgs %v (cmd=%[2]q)\", osArgs, cmd.Name)\n\t\tcmd.shellCompletion, osArgs = checkShellCompleteFlag(cmd, osArgs)\n\n\t\ttracef(\"setting cmd.shellCompletion=%[1]v from checkShellCompleteFlag (cmd=%[2]q)\", cmd.shellCompletion && cmd.EnableShellCompletion, cmd.Name)\n\t\tcmd.shellCompletion = cmd.EnableShellCompletion && cmd.shellCompletion\n\t}\n\n\ttracef(\"using post-checkShellCompleteFlag arguments %[1]q (cmd=%[2]q)\", osArgs, cmd.Name)\n\n\ttracef(\"setting self as cmd in context (cmd=%[1]q)\", cmd.Name)\n\tctx = context.WithValue(ctx, commandContextKey, cmd)\n\n\tif cmd.parent == nil {\n\t\tcmd.setupCommandGraph()\n\t}\n\n\tvar rargs Args = &stringSliceArgs{v: osArgs}\n\tvar args Args = &stringSliceArgs{rargs.Tail()}\n\n\tif cmd.isCompletionCommand || cmd.Name == helpName {\n\t\ttracef(\"special command detected, skipping pre-parse (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.parsedArgs = args\n\t\treturn ctx, cmd.Action(ctx, cmd)\n\t}\n\n\tfor _, f := range cmd.allFlags() {\n\t\tif err := f.PreParse(); err != nil {\n\t\t\treturn ctx, err\n\t\t}\n\t}\n\n\tvar err error\n\n\tif cmd.SkipFlagParsing {\n\t\ttracef(\"skipping flag parsing (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.parsedArgs = args\n\t} else {\n\t\tcmd.parsedArgs, err = cmd.parseFlags(args)\n\t}\n\n\ttracef(\"using post-parse arguments %[1]q (cmd=%[2]q)\", args, cmd.Name)\n\n\tif checkCompletions(ctx, cmd) {\n\t\treturn ctx, nil\n\t}\n\n\tif err != nil {\n\t\ttracef(\"setting deferErr from %[1]q (cmd=%[2]q)\", err, cmd.Name)\n\t\tdeferErr = err\n\n\t\tcmd.isInError = true\n\t\tif cmd.OnUsageError != nil {\n\t\t\terr = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)\n\t\t\terr = cmd.handleExitCoder(ctx, err)\n\t\t\treturn ctx, err\n\t\t}\n\t\tfmt.Fprintf(cmd.Root().ErrWriter, \"Incorrect Usage: %s\\n\\n\", err.Error())\n\t\tif cmd.Suggest {\n\t\t\tif suggestion, err := cmd.suggestFlagFromError(err, \"\"); err == nil {\n\t\t\t\tfmt.Fprintf(cmd.Root().ErrWriter, \"%s\", suggestion)\n\t\t\t}\n\t\t}\n\t\tif !cmd.hideHelp() {\n\t\t\tif cmd.parent == nil {\n\t\t\t\ttracef(\"running ShowRootCommandHelp\")\n\t\t\t\tif err := ShowRootCommandHelp(cmd); err != nil {\n\t\t\t\t\ttracef(\"SILENTLY IGNORING ERROR running ShowRootCommandHelp %[1]v (cmd=%[2]q)\", err, cmd.Name)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttracef(\"running ShowCommandHelp with %[1]q\", cmd.Name)\n\t\t\t\tif err := ShowCommandHelp(ctx, cmd, cmd.Name); err != nil {\n\t\t\t\t\ttracef(\"SILENTLY IGNORING ERROR running ShowCommandHelp with %[1]q %[2]v\", cmd.Name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ctx, err\n\t}\n\n\tif cmd.checkHelp() {\n\t\treturn ctx, helpCommandAction(ctx, cmd)\n\t} else {\n\t\ttracef(\"no help is wanted (cmd=%[1]q)\", cmd.Name)\n\t}\n\n\tif cmd.parent == nil && !cmd.HideVersion && checkVersion(cmd) {\n\t\tShowVersion(cmd)\n\t\treturn ctx, nil\n\t}\n\n\tfor _, flag := range cmd.allFlags() {\n\t\tisSet := flag.IsSet()\n\t\tif err := flag.PostParse(); err != nil {\n\t\t\treturn ctx, err\n\t\t}\n\t\t// add env set flags here\n\t\tif !isSet && flag.IsSet() {\n\t\t\tcmd.setFlags[flag] = struct{}{}\n\t\t}\n\t}\n\n\tif cmd.After != nil && !cmd.Root().shellCompletion {\n\t\tdefer func() {\n\t\t\tif err := cmd.After(ctx, cmd); err != nil {\n\t\t\t\terr = cmd.handleExitCoder(ctx, err)\n\n\t\t\t\tif deferErr != nil {\n\t\t\t\t\tdeferErr = newMultiError(deferErr, err)\n\t\t\t\t} else {\n\t\t\t\t\tdeferErr = err\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Walk the parent chain to check mutually exclusive flag groups\n\t// defined on ancestor commands, since persistent flags are inherited.\n\tfor pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {\n\t\tfor _, grp := range pCmd.MutuallyExclusiveFlags {\n\t\t\tif err := grp.check(cmd); err != nil {\n\t\t\t\tif cmd.OnUsageError != nil {\n\t\t\t\t\terr = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)\n\t\t\t\t} else {\n\t\t\t\t\t_ = ShowSubcommandHelp(cmd)\n\t\t\t\t}\n\t\t\t\treturn ctx, err\n\t\t\t}\n\t\t}\n\t}\n\n\tvar subCmd *Command\n\tif cmd.parsedArgs.Present() {\n\t\ttracef(\"checking positional args %[1]q (cmd=%[2]q)\", cmd.parsedArgs, cmd.Name)\n\n\t\tname := cmd.parsedArgs.First()\n\n\t\ttracef(\"using first positional argument as sub-command name=%[1]q (cmd=%[2]q)\", name, cmd.Name)\n\n\t\tif cmd.SuggestCommandFunc != nil && name != \"--\" {\n\t\t\tname = cmd.SuggestCommandFunc(cmd.Commands, name)\n\t\t\ttracef(\"suggested command name=%1[q] (cmd=%[2]q)\", name, cmd.Name)\n\t\t}\n\t\tsubCmd = cmd.Command(name)\n\t\tif subCmd == nil {\n\t\t\thasDefault := cmd.DefaultCommand != \"\"\n\t\t\tisFlagName := slices.Contains(cmd.FlagNames(), name)\n\n\t\t\tif hasDefault {\n\t\t\t\ttracef(\"using default command=%[1]q (cmd=%[2]q)\", cmd.DefaultCommand, cmd.Name)\n\t\t\t}\n\n\t\t\tif isFlagName || hasDefault {\n\t\t\t\targsWithDefault := cmd.argsWithDefaultCommand(cmd.parsedArgs)\n\t\t\t\ttracef(\"using default command args=%[1]q (cmd=%[2]q)\", argsWithDefault, cmd.Name)\n\t\t\t\tsubCmd = cmd.Command(argsWithDefault.First())\n\t\t\t\tcmd.parsedArgs = argsWithDefault\n\t\t\t}\n\t\t}\n\t} else if cmd.DefaultCommand != \"\" {\n\t\ttracef(\"no positional args present; checking default command %[1]q (cmd=%[2]q)\", cmd.DefaultCommand, cmd.Name)\n\n\t\tif dc := cmd.Command(cmd.DefaultCommand); dc != cmd {\n\t\t\tsubCmd = dc\n\t\t}\n\t}\n\n\t// If a subcommand has been resolved, let it handle the remaining execution.\n\tif subCmd != nil {\n\t\ttracef(\"running sub-command %[1]q with arguments %[2]q (cmd=%[3]q)\", subCmd.Name, cmd.Args(), cmd.Name)\n\n\t\t// It is important that we overwrite the ctx variable in the current\n\t\t// function so any defer'd functions use the new context returned\n\t\t// from the sub command.\n\t\tctx, err = subCmd.run(ctx, cmd.Args().Slice())\n\t\treturn ctx, err\n\t}\n\n\t// This code path is the innermost command execution. Here we actually\n\t// perform the command action.\n\t//\n\t// First, resolve the chain of nested commands up to the parent.\n\tvar cmdChain []*Command\n\tfor p := cmd; p != nil; p = p.parent {\n\t\tcmdChain = append(cmdChain, p)\n\t}\n\tslices.Reverse(cmdChain)\n\n\t// Run Before actions in order.\n\tfor _, cmd := range cmdChain {\n\t\tif cmd.Before == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif bctx, err := cmd.Before(ctx, cmd); err != nil {\n\t\t\tdeferErr = cmd.handleExitCoder(ctx, err)\n\t\t\treturn ctx, deferErr\n\t\t} else if bctx != nil {\n\t\t\tctx = bctx\n\t\t}\n\t}\n\n\t// Run flag actions in order.\n\t// These take a context, so this has to happen after Before actions.\n\tfor _, cmd := range cmdChain {\n\t\ttracef(\"running flag actions (cmd=%[1]q)\", cmd.Name)\n\t\tif err := cmd.runFlagActions(ctx); err != nil {\n\t\t\tdeferErr = cmd.handleExitCoder(ctx, err)\n\t\t\treturn ctx, deferErr\n\t\t}\n\t}\n\n\tif err := cmd.checkAllRequiredFlags(); err != nil {\n\t\tcmd.isInError = true\n\t\tif cmd.OnUsageError != nil {\n\t\t\terr = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)\n\t\t} else {\n\t\t\t_ = ShowSubcommandHelp(cmd)\n\t\t}\n\t\treturn ctx, err\n\t}\n\n\t// Run the command action.\n\tif len(cmd.Arguments) > 0 {\n\t\trargs := cmd.Args().Slice()\n\t\ttracef(\"calling argparse with %[1]v\", rargs)\n\t\tfor _, arg := range cmd.Arguments {\n\t\t\tvar err error\n\t\t\trargs, err = arg.Parse(rargs)\n\t\t\tif err != nil {\n\t\t\t\ttracef(\"calling with %[1]v (cmd=%[2]q)\", err, cmd.Name)\n\t\t\t\tif cmd.OnUsageError != nil {\n\t\t\t\t\terr = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)\n\t\t\t\t}\n\t\t\t\terr = cmd.handleExitCoder(ctx, err)\n\t\t\t\treturn ctx, err\n\t\t\t}\n\t\t}\n\t\tcmd.parsedArgs = &stringSliceArgs{v: rargs}\n\t}\n\n\tif err := cmd.Action(ctx, cmd); err != nil {\n\t\ttracef(\"calling handleExitCoder with %[1]v (cmd=%[2]q)\", err, cmd.Name)\n\t\tdeferErr = cmd.handleExitCoder(ctx, err)\n\t}\n\n\ttracef(\"returning deferErr (cmd=%[1]q) %[2]q\", cmd.Name, deferErr)\n\treturn ctx, deferErr\n}\n"
  },
  {
    "path": "command_setup.go",
    "content": "package cli\n\nimport (\n\t\"flag\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n)\n\nfunc (cmd *Command) setupDefaults(osArgs []string) {\n\tif cmd.didSetupDefaults {\n\t\ttracef(\"already did setup (cmd=%[1]q)\", cmd.Name)\n\t\treturn\n\t}\n\n\tcmd.didSetupDefaults = true\n\n\tisRoot := cmd.parent == nil\n\ttracef(\"isRoot? %[1]v (cmd=%[2]q)\", isRoot, cmd.Name)\n\n\tif cmd.ShellComplete == nil {\n\t\ttracef(\"setting default ShellComplete (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.ShellComplete = DefaultCompleteWithFlags\n\t}\n\n\tif cmd.Name == \"\" && isRoot {\n\t\tname := filepath.Base(osArgs[0])\n\t\ttracef(\"setting cmd.Name from first arg basename (cmd=%[1]q)\", name)\n\t\tcmd.Name = name\n\t}\n\n\tif cmd.Usage == \"\" && isRoot {\n\t\ttracef(\"setting default Usage (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.Usage = \"A new cli application\"\n\t}\n\n\tif cmd.Version == \"\" {\n\t\ttracef(\"setting HideVersion=true due to empty Version (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.HideVersion = true\n\t}\n\n\tif cmd.Action == nil {\n\t\ttracef(\"setting default Action as help command action (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.Action = helpCommandAction\n\t}\n\n\tif cmd.Reader == nil {\n\t\ttracef(\"setting default Reader as os.Stdin (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.Reader = os.Stdin\n\t}\n\n\tif cmd.Writer == nil {\n\t\ttracef(\"setting default Writer as os.Stdout (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.Writer = os.Stdout\n\t}\n\n\tif cmd.ErrWriter == nil {\n\t\ttracef(\"setting default ErrWriter as os.Stderr (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.ErrWriter = os.Stderr\n\t}\n\n\tif cmd.AllowExtFlags {\n\t\ttracef(\"visiting all flags given AllowExtFlags=true (cmd=%[1]q)\", cmd.Name)\n\t\t// add global flags added by other packages\n\t\tflag.VisitAll(func(f *flag.Flag) {\n\t\t\t// skip test flags\n\t\t\tif !strings.HasPrefix(f.Name, ignoreFlagPrefix) {\n\t\t\t\tcmd.Flags = append(cmd.Flags, &extFlag{f})\n\t\t\t}\n\t\t})\n\t}\n\n\tfor _, subCmd := range cmd.Commands {\n\t\ttracef(\"setting sub-command (cmd=%[1]q) parent as self (cmd=%[2]q)\", subCmd.Name, cmd.Name)\n\t\tsubCmd.parent = cmd\n\t}\n\n\tcmd.ensureHelp()\n\n\tif !cmd.HideVersion && isRoot {\n\t\ttracef(\"appending version flag (cmd=%[1]q)\", cmd.Name)\n\t\tif !cmd.globaVersionFlagAdded {\n\t\t\tvar localVersionFlag Flag\n\t\t\tif globalVersionFlag, ok := VersionFlag.(*BoolFlag); ok {\n\t\t\t\tflag := *globalVersionFlag\n\t\t\t\tlocalVersionFlag = &flag\n\t\t\t} else {\n\t\t\t\tlocalVersionFlag = VersionFlag\n\t\t\t}\n\n\t\t\tcmd.appendFlag(localVersionFlag)\n\t\t\tcmd.globaVersionFlagAdded = true\n\t\t}\n\t}\n\n\tif cmd.PrefixMatchCommands && cmd.SuggestCommandFunc == nil {\n\t\ttracef(\"setting default SuggestCommandFunc (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.SuggestCommandFunc = suggestCommand\n\t}\n\n\tif isRoot && cmd.EnableShellCompletion || cmd.ConfigureShellCompletionCommand != nil {\n\t\tcompletionCommand := buildCompletionCommand(cmd.Name)\n\n\t\tif cmd.ShellCompletionCommandName != \"\" {\n\t\t\ttracef(\n\t\t\t\t\"setting completion command name (%[1]q) from \"+\n\t\t\t\t\t\"cmd.ShellCompletionCommandName (cmd=%[2]q)\",\n\t\t\t\tcmd.ShellCompletionCommandName, cmd.Name,\n\t\t\t)\n\t\t\tcompletionCommand.Name = cmd.ShellCompletionCommandName\n\t\t}\n\n\t\ttracef(\"appending completionCommand (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.appendCommand(completionCommand)\n\t\tif cmd.ConfigureShellCompletionCommand != nil {\n\t\t\tcmd.ConfigureShellCompletionCommand(completionCommand)\n\t\t}\n\t}\n\n\ttracef(\"setting command categories (cmd=%[1]q)\", cmd.Name)\n\tcmd.categories = newCommandCategories()\n\n\tfor _, subCmd := range cmd.Commands {\n\t\tcmd.categories.AddCommand(subCmd.Category, subCmd)\n\t}\n\n\ttracef(\"sorting command categories (cmd=%[1]q)\", cmd.Name)\n\tsort.Sort(cmd.categories.(*commandCategories))\n\n\ttracef(\"setting category on mutually exclusive flags (cmd=%[1]q)\", cmd.Name)\n\tfor _, grp := range cmd.MutuallyExclusiveFlags {\n\t\tgrp.propagateCategory()\n\t}\n\n\ttracef(\"setting flag categories (cmd=%[1]q)\", cmd.Name)\n\tcmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())\n\n\tif cmd.Metadata == nil {\n\t\ttracef(\"setting default Metadata (cmd=%[1]q)\", cmd.Name)\n\t\tcmd.Metadata = map[string]any{}\n\t}\n\n\tcmd.setFlags = map[Flag]struct{}{}\n}\n\nfunc (cmd *Command) setupCommandGraph() {\n\ttracef(\"setting up command graph (cmd=%[1]q)\", cmd.Name)\n\n\tfor _, subCmd := range cmd.Commands {\n\t\tsubCmd.parent = cmd\n\t\tsubCmd.setupSubcommand()\n\t\tsubCmd.setupCommandGraph()\n\t}\n}\n\nfunc (cmd *Command) setupSubcommand() {\n\ttracef(\"setting up self as sub-command (cmd=%[1]q)\", cmd.Name)\n\n\tcmd.ensureHelp()\n\n\ttracef(\"setting command categories (cmd=%[1]q)\", cmd.Name)\n\tcmd.categories = newCommandCategories()\n\n\tfor _, subCmd := range cmd.Commands {\n\t\tcmd.categories.AddCommand(subCmd.Category, subCmd)\n\t}\n\n\ttracef(\"sorting command categories (cmd=%[1]q)\", cmd.Name)\n\tsort.Sort(cmd.categories.(*commandCategories))\n\n\ttracef(\"setting category on mutually exclusive flags (cmd=%[1]q)\", cmd.Name)\n\tfor _, grp := range cmd.MutuallyExclusiveFlags {\n\t\tgrp.propagateCategory()\n\t}\n\n\ttracef(\"setting flag categories (cmd=%[1]q)\", cmd.Name)\n\tcmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())\n}\n\nfunc (cmd *Command) hideHelp() bool {\n\ttracef(\"hide help (cmd=%[1]q)\", cmd.Name)\n\tfor c := cmd; c != nil; c = c.parent {\n\t\tif c.HideHelp {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (cmd *Command) ensureHelp() {\n\ttracef(\"ensuring help (cmd=%[1]q)\", cmd.Name)\n\n\thelpCommand := buildHelpCommand(true)\n\n\tif !cmd.hideHelp() {\n\t\tif cmd.Command(helpCommand.Name) == nil {\n\t\t\tif !cmd.HideHelpCommand {\n\t\t\t\ttracef(\"appending helpCommand (cmd=%[1]q)\", cmd.Name)\n\t\t\t\tcmd.appendCommand(helpCommand)\n\t\t\t}\n\t\t}\n\n\t\tif HelpFlag != nil {\n\t\t\tif !cmd.globaHelpFlagAdded {\n\t\t\t\tvar localHelpFlag Flag\n\t\t\t\tif globalHelpFlag, ok := HelpFlag.(*BoolFlag); ok {\n\t\t\t\t\tflag := *globalHelpFlag\n\t\t\t\t\tlocalHelpFlag = &flag\n\t\t\t\t} else {\n\t\t\t\t\tlocalHelpFlag = HelpFlag\n\t\t\t\t}\n\n\t\t\t\ttracef(\"appending HelpFlag (cmd=%[1]q)\", cmd.Name)\n\t\t\t\tcmd.appendFlag(localHelpFlag)\n\t\t\t\tcmd.globaHelpFlagAdded = true\n\t\t\t} else {\n\t\t\t\ttracef(\"HelpFlag already added, skip (cmd=%[1]q)\", cmd.Name)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "command_stop_on_nth_arg_test.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCommand_StopOnNthArg(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tstopOnNthArg *int\n\t\ttestArgs     []string\n\t\texpectedArgs []string\n\t\texpectedFlag string\n\t\texpectedBool bool\n\t}{\n\t\t{\n\t\t\tname:         \"nil StopOnNthArg - normal parsing\",\n\t\t\tstopOnNthArg: nil,\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"arg1\", \"--bool\", \"arg2\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"arg2\"},\n\t\t\texpectedFlag: \"value\",\n\t\t\texpectedBool: true,\n\t\t},\n\t\t{\n\t\t\tname:         \"stop after 0 args - all become args\",\n\t\t\tstopOnNthArg: intPtr(0),\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"arg1\", \"--bool\", \"arg2\"},\n\t\t\texpectedArgs: []string{\"--flag\", \"value\", \"arg1\", \"--bool\", \"arg2\"},\n\t\t\texpectedFlag: \"\",\n\t\t\texpectedBool: false,\n\t\t},\n\t\t{\n\t\t\tname:         \"stop after 1 arg\",\n\t\t\tstopOnNthArg: intPtr(1),\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"arg1\", \"--bool\", \"arg2\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"--bool\", \"arg2\"},\n\t\t\texpectedFlag: \"value\",\n\t\t\texpectedBool: false,\n\t\t},\n\t\t{\n\t\t\tname:         \"stop after 2 args\",\n\t\t\tstopOnNthArg: intPtr(2),\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"arg1\", \"arg2\", \"--bool\", \"arg3\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"arg2\", \"--bool\", \"arg3\"},\n\t\t\texpectedFlag: \"value\",\n\t\t\texpectedBool: false,\n\t\t},\n\t\t{\n\t\t\tname:         \"mixed flags and args - stop after 1\",\n\t\t\tstopOnNthArg: intPtr(1),\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"--bool\", \"arg1\", \"--flag2\", \"value2\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"--flag2\", \"value2\"},\n\t\t\texpectedFlag: \"value\",\n\t\t\texpectedBool: true,\n\t\t},\n\t\t{\n\t\t\tname:         \"args before flags - stop after 1\",\n\t\t\tstopOnNthArg: intPtr(1),\n\t\t\ttestArgs:     []string{\"cmd\", \"arg1\", \"--flag\", \"value\", \"--bool\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"--flag\", \"value\", \"--bool\"},\n\t\t\texpectedFlag: \"\",\n\t\t\texpectedBool: false,\n\t\t},\n\t\t{\n\t\t\tname:         \"ssh command example\",\n\t\t\tstopOnNthArg: intPtr(1),\n\t\t\ttestArgs:     []string{\"ssh\", \"machine-name\", \"ls\", \"-la\"},\n\t\t\texpectedArgs: []string{\"machine-name\", \"ls\", \"-la\"},\n\t\t\texpectedFlag: \"\",\n\t\t\texpectedBool: false,\n\t\t},\n\t\t{\n\t\t\tname:         \"with double dash terminator\",\n\t\t\tstopOnNthArg: intPtr(1),\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"--\", \"arg1\", \"--not-a-flag\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"--not-a-flag\"},\n\t\t\texpectedFlag: \"value\",\n\t\t\texpectedBool: false,\n\t\t},\n\t\t{\n\t\t\tname:         \"stop after large number of args\",\n\t\t\tstopOnNthArg: intPtr(100),\n\t\t\ttestArgs:     []string{\"cmd\", \"--flag\", \"value\", \"arg1\", \"arg2\", \"--bool\"},\n\t\t\texpectedArgs: []string{\"arg1\", \"arg2\"},\n\t\t\texpectedFlag: \"value\",\n\t\t\texpectedBool: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar args Args\n\t\t\tvar flagValue string\n\t\t\tvar boolValue bool\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:         \"test\",\n\t\t\t\tStopOnNthArg: tt.stopOnNthArg,\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{Name: \"flag\", Destination: &flagValue},\n\t\t\t\t\t&StringFlag{Name: \"flag2\"},\n\t\t\t\t\t&BoolFlag{Name: \"bool\", Destination: &boolValue},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\targs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\trequire.NoError(t, cmd.Run(buildTestContext(t), tt.testArgs))\n\t\t\tassert.Equal(t, tt.expectedArgs, args.Slice())\n\t\t\tassert.Equal(t, tt.expectedFlag, flagValue)\n\t\t\tassert.Equal(t, tt.expectedBool, boolValue)\n\t\t})\n\t}\n}\n\nfunc TestCommand_StopOnNthArg_WithSubcommands(t *testing.T) {\n\ttests := []struct {\n\t\tname               string\n\t\tparentStopOnNthArg *int\n\t\tsubStopOnNthArg    *int\n\t\ttestArgs           []string\n\t\texpectedParentArgs []string\n\t\texpectedSubArgs    []string\n\t\texpectedSubFlag    string\n\t}{\n\t\t{\n\t\t\tname:               \"parent normal, subcommand stops after 0\",\n\t\t\tparentStopOnNthArg: nil,\n\t\t\tsubStopOnNthArg:    intPtr(0),\n\t\t\ttestArgs:           []string{\"parent\", \"sub\", \"--subflag\", \"value\", \"subarg\", \"--not-parsed\"},\n\t\t\texpectedParentArgs: []string{},\n\t\t\texpectedSubArgs:    []string{\"--subflag\", \"value\", \"subarg\", \"--not-parsed\"},\n\t\t\texpectedSubFlag:    \"\",\n\t\t},\n\t\t{\n\t\t\tname:               \"parent normal, subcommand stops after 1\",\n\t\t\tparentStopOnNthArg: nil,\n\t\t\tsubStopOnNthArg:    intPtr(1),\n\t\t\ttestArgs:           []string{\"parent\", \"sub\", \"--subflag\", \"value\", \"subarg\", \"--not-parsed\"},\n\t\t\texpectedParentArgs: []string{},\n\t\t\texpectedSubArgs:    []string{\"subarg\", \"--not-parsed\"},\n\t\t\texpectedSubFlag:    \"value\",\n\t\t},\n\t\t{\n\t\t\tname:               \"parent normal, subcommand stops after 2\",\n\t\t\tparentStopOnNthArg: nil,\n\t\t\tsubStopOnNthArg:    intPtr(2),\n\t\t\ttestArgs:           []string{\"parent\", \"sub\", \"--subflag\", \"value\", \"subarg1\", \"subarg2\", \"--not-parsed\"},\n\t\t\texpectedParentArgs: []string{},\n\t\t\texpectedSubArgs:    []string{\"subarg1\", \"subarg2\", \"--not-parsed\"},\n\t\t\texpectedSubFlag:    \"value\",\n\t\t},\n\t\t{\n\t\t\tname:               \"parent normal, subcommand never stops (high StopOnNthArg)\",\n\t\t\tparentStopOnNthArg: nil,\n\t\t\tsubStopOnNthArg:    intPtr(100),\n\t\t\ttestArgs:           []string{\"parent\", \"sub\", \"--subflag\", \"value1\", \"arg1\", \"arg2\", \"--subflag\", \"value2\"},\n\t\t\texpectedParentArgs: []string{},\n\t\t\texpectedSubArgs:    []string{\"arg1\", \"arg2\"},\n\t\t\texpectedSubFlag:    \"value2\", // Should parse the second --subflag since we never hit the stop limit\n\t\t},\n\t\t{\n\t\t\t// Meaningless, but okay.\n\t\t\tname:               \"parent stops after 1, subcommand stops after 1\",\n\t\t\tparentStopOnNthArg: intPtr(1),\n\t\t\tsubStopOnNthArg:    intPtr(1),\n\t\t\ttestArgs:           []string{\"parent\", \"sub\", \"--subflag\", \"value\", \"subarg\", \"--not-parsed\"},\n\t\t\texpectedParentArgs: []string{},\n\t\t\texpectedSubArgs:    []string{\"subarg\", \"--not-parsed\"},\n\t\t\texpectedSubFlag:    \"value\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar parentArgs, subArgs Args\n\t\t\tvar subFlagValue string\n\t\t\tsubCalled := false\n\n\t\t\tsubCmd := &Command{\n\t\t\t\tName:         \"sub\",\n\t\t\t\tStopOnNthArg: tt.subStopOnNthArg,\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{Name: \"subflag\", Destination: &subFlagValue},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tsubCalled = true\n\t\t\t\t\tsubArgs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tparentCmd := &Command{\n\t\t\t\tName:         \"parent\",\n\t\t\t\tStopOnNthArg: tt.parentStopOnNthArg,\n\t\t\t\tCommands:     []*Command{subCmd},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{Name: \"parentflag\"},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tparentArgs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := parentCmd.Run(buildTestContext(t), tt.testArgs)\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif tt.expectedSubArgs != nil {\n\t\t\t\tassert.True(t, subCalled, \"subcommand should have been called\")\n\t\t\t\tif len(tt.expectedSubArgs) > 0 {\n\t\t\t\t\thaveNonEmptySubArgsSlice := subArgs != nil && subArgs.Slice() != nil && len(subArgs.Slice()) > 0\n\t\t\t\t\tassert.True(t, haveNonEmptySubArgsSlice, \"subargs.Slice is not nil\")\n\t\t\t\t\tif haveNonEmptySubArgsSlice {\n\t\t\t\t\t\tassert.Equal(t, tt.expectedSubArgs, subArgs.Slice())\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tassert.True(t, subArgs == nil || subArgs.Slice() == nil || len(subArgs.Slice()) == 0, \"subargs.Slice is not nil\")\n\t\t\t\t}\n\t\t\t\tassert.Equal(t, tt.expectedSubFlag, subFlagValue)\n\t\t\t} else {\n\t\t\t\tassert.False(t, subCalled, \"subcommand should not have been called\")\n\t\t\t\tassert.Equal(t, tt.expectedParentArgs, parentArgs.Slice())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_StopOnNthArg_EdgeCases(t *testing.T) {\n\tt.Run(\"negative StopOnNthArg returns error\", func(t *testing.T) {\n\t\tcmd := &Command{\n\t\t\tName:         \"test\",\n\t\t\tStopOnNthArg: intPtr(-1),\n\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\n\t\t// Negative value should return an error\n\t\terr := cmd.Run(buildTestContext(t), []string{\"cmd\", \"arg1\"})\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"StopOnNthArg must be non-negative\")\n\t})\n\n\tt.Run(\"zero StopOnNthArg with no args\", func(t *testing.T) {\n\t\tvar args Args\n\t\tvar flagValue string\n\t\tcmd := &Command{\n\t\t\tName:         \"test\",\n\t\t\tStopOnNthArg: intPtr(0),\n\t\t\tFlags: []Flag{\n\t\t\t\t&StringFlag{Name: \"flag\", Destination: &flagValue},\n\t\t\t},\n\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\targs = cmd.Args()\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\n\t\t// All flags should become args\n\t\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"cmd\", \"--flag\", \"value\"}))\n\t\tassert.Equal(t, []string{\"--flag\", \"value\"}, args.Slice())\n\t\tassert.Equal(t, \"\", flagValue)\n\t})\n\n\tt.Run(\"StopOnNthArg with only flags\", func(t *testing.T) {\n\t\tvar args Args\n\t\tvar flagValue string\n\t\tvar boolValue bool\n\t\tcmd := &Command{\n\t\t\tName:         \"test\",\n\t\t\tStopOnNthArg: intPtr(1),\n\t\t\tFlags: []Flag{\n\t\t\t\t&StringFlag{Name: \"flag\", Destination: &flagValue},\n\t\t\t\t&BoolFlag{Name: \"bool\", Destination: &boolValue},\n\t\t\t},\n\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\targs = cmd.Args()\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\n\t\t// Should parse all flags since no args are encountered\n\t\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"cmd\", \"--flag\", \"value\", \"--bool\"}))\n\t\tassert.Equal(t, []string{}, args.Slice())\n\t\tassert.Equal(t, \"value\", flagValue)\n\t\tassert.True(t, boolValue)\n\t})\n}\n\n// Helper function to create int pointer\nfunc intPtr(i int) *int {\n\treturn &i\n}\n"
  },
  {
    "path": "command_test.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/mail\"\n\t\"os\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar (\n\tlastExitCode = 0\n\tfakeOsExiter = func(rc int) {\n\t\tlastExitCode = rc\n\t}\n\tfakeErrWriter = &bytes.Buffer{}\n)\n\nfunc init() {\n\tOsExiter = fakeOsExiter\n\tErrWriter = fakeErrWriter\n}\n\ntype opCounts struct {\n\tTotal, ShellComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int\n}\n\nfunc buildExtendedTestCommand() *Command {\n\tcmd := buildMinimalTestCommand()\n\tcmd.Name = \"greet\"\n\tcmd.Flags = []Flag{\n\t\t&StringFlag{\n\t\t\tName:      \"socket\",\n\t\t\tAliases:   []string{\"s\"},\n\t\t\tUsage:     \"some 'usage' text\",\n\t\t\tValue:     \"value\",\n\t\t\tTakesFile: true,\n\t\t},\n\t\t&StringFlag{Name: \"flag\", Aliases: []string{\"fl\", \"f\"}},\n\t\t&BoolFlag{\n\t\t\tName:    \"another-flag\",\n\t\t\tAliases: []string{\"b\"},\n\t\t\tUsage:   \"another usage text\",\n\t\t\tSources: EnvVars(\"EXAMPLE_VARIABLE_NAME\"),\n\t\t},\n\t\t&BoolFlag{\n\t\t\tName:   \"hidden-flag\",\n\t\t\tHidden: true,\n\t\t},\n\t}\n\tcmd.Commands = []*Command{{\n\t\tAliases: []string{\"c\"},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:      \"flag\",\n\t\t\t\tAliases:   []string{\"fl\", \"f\"},\n\t\t\t\tTakesFile: true,\n\t\t\t},\n\t\t\t&BoolFlag{\n\t\t\t\tName:    \"another-flag\",\n\t\t\t\tAliases: []string{\"b\"},\n\t\t\t\tUsage:   \"another usage text\",\n\t\t\t},\n\t\t},\n\t\tName:  \"config\",\n\t\tUsage: \"another usage test\",\n\t\tCommands: []*Command{{\n\t\t\tAliases: []string{\"s\", \"ss\"},\n\t\t\tFlags: []Flag{\n\t\t\t\t&StringFlag{Name: \"sub-flag\", Aliases: []string{\"sub-fl\", \"s\"}},\n\t\t\t\t&BoolFlag{\n\t\t\t\t\tName:    \"sub-command-flag\",\n\t\t\t\t\tAliases: []string{\"s\"},\n\t\t\t\t\tUsage:   \"some usage text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tName:  \"sub-config\",\n\t\t\tUsage: \"another usage test\",\n\t\t}},\n\t}, {\n\t\tAliases: []string{\"i\", \"in\"},\n\t\tName:    \"info\",\n\t\tUsage:   \"retrieve generic information\",\n\t}, {\n\t\tName: \"some-command\",\n\t}, {\n\t\tName:   \"hidden-command\",\n\t\tHidden: true,\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"completable\",\n\t\t\t},\n\t\t},\n\t}, {\n\t\tAliases: []string{\"u\"},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:      \"flag\",\n\t\t\t\tAliases:   []string{\"fl\", \"f\"},\n\t\t\t\tTakesFile: true,\n\t\t\t},\n\t\t\t&BoolFlag{\n\t\t\t\tName:    \"another-flag\",\n\t\t\t\tAliases: []string{\"b\"},\n\t\t\t\tUsage:   \"another usage text\",\n\t\t\t},\n\t\t},\n\t\tName:  \"usage\",\n\t\tUsage: \"standard usage text\",\n\t\tUsageText: `\nUsage for the usage text\n- formatted:  Based on the specified ConfigMap and summon secrets.yml\n- list:       Inspect the environment for a specific process running on a Pod\n- for_effect: Compare 'namespace' environment with 'local'\n\n` + \"```\" + `\nfunc() { ... }\n` + \"```\" + `\n\nShould be a part of the same code block\n`,\n\t\tCommands: []*Command{{\n\t\t\tAliases: []string{\"su\"},\n\t\t\tFlags: []Flag{\n\t\t\t\t&BoolFlag{\n\t\t\t\t\tName:    \"sub-command-flag\",\n\t\t\t\t\tAliases: []string{\"s\"},\n\t\t\t\t\tUsage:   \"some usage text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tName:      \"sub-usage\",\n\t\t\tUsage:     \"standard usage text\",\n\t\t\tUsageText: \"Single line of UsageText\",\n\t\t}},\n\t}}\n\tcmd.UsageText = \"app [first_arg] [second_arg]\"\n\tcmd.Description = `Description of the application.`\n\tcmd.Usage = \"Some app\"\n\tcmd.Authors = []any{\n\t\t\"Harrison <harrison@lolwut.example.com>\",\n\t\t&mail.Address{Name: \"Oliver Allen\", Address: \"oliver@toyshop.com\"},\n\t}\n\n\treturn cmd\n}\n\nfunc TestCommandFlagParsing(t *testing.T) {\n\tcases := []struct {\n\t\ttestArgs               []string\n\t\tskipFlagParsing        bool\n\t\tuseShortOptionHandling bool\n\t\texpectedErr            string\n\t}{\n\t\t// Test normal \"not ignoring flags\" flow\n\t\t{testArgs: []string{\"test-cmd\", \"-break\", \"blah\", \"blah\"}, skipFlagParsing: false, useShortOptionHandling: false, expectedErr: \"flag provided but not defined: -break\"},\n\t\t{testArgs: []string{\"test-cmd\", \"blah\", \"blah\"}, skipFlagParsing: true, useShortOptionHandling: false},                                        // Test SkipFlagParsing without any args that look like flags\n\t\t{testArgs: []string{\"test-cmd\", \"blah\", \"-break\"}, skipFlagParsing: true, useShortOptionHandling: false},                                      // Test SkipFlagParsing with random flag arg\n\t\t{testArgs: []string{\"test-cmd\", \"blah\", \"-help\"}, skipFlagParsing: true, useShortOptionHandling: false},                                       // Test SkipFlagParsing with \"special\" help flag arg\n\t\t{testArgs: []string{\"test-cmd\", \"blah\", \"-h\"}, skipFlagParsing: false, useShortOptionHandling: true, expectedErr: \"No help topic for 'blah'\"}, // Test UseShortOptionHandling\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(strings.Join(c.testArgs, \" \"), func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tWriter:          io.Discard,\n\t\t\t\tName:            \"test-cmd\",\n\t\t\t\tAliases:         []string{\"tc\"},\n\t\t\t\tUsage:           \"this is for testing\",\n\t\t\t\tDescription:     \"testing\",\n\t\t\t\tAction:          func(context.Context, *Command) error { return nil },\n\t\t\t\tSkipFlagParsing: c.skipFlagParsing,\n\t\t\t}\n\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\n\t\t\tt.Cleanup(cancel)\n\n\t\t\tr := require.New(t)\n\n\t\t\terr := cmd.Run(ctx, c.testArgs)\n\n\t\t\tif c.expectedErr != \"\" {\n\t\t\t\tr.EqualError(err, c.expectedErr)\n\t\t\t} else {\n\t\t\t\tr.NoError(err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseAndRunShortOpts(t *testing.T) {\n\ttestCases := []struct {\n\t\ttestArgs     *stringSliceArgs\n\t\texpectedErr  string\n\t\texpectedArgs Args\n\t}{\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-a\"}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-c\", \"arg1\", \"arg2\"}}, expectedArgs: &stringSliceArgs{v: []string{\"arg1\", \"arg2\"}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-f\"}}, expectedArgs: &stringSliceArgs{v: []string{}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-ac\", \"--fgh\"}}, expectedArgs: &stringSliceArgs{v: []string{}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-af\"}}, expectedArgs: &stringSliceArgs{v: []string{}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-cf\"}}, expectedArgs: &stringSliceArgs{v: []string{}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-acf\"}}, expectedArgs: &stringSliceArgs{v: []string{}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"--acf\"}}, expectedErr: \"flag provided but not defined: -acf\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-acf\", \"-invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"--invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-acf\", \"--invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-acf\", \"arg1\", \"-invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-acf\", \"arg1\", \"--invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-acfi\", \"not-arg\", \"arg1\", \"-invalid\"}}, expectedErr: \"flag provided but not defined: -invalid\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-i\", \"ivalue\"}}, expectedArgs: &stringSliceArgs{v: []string{}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-i\", \"ivalue\", \"arg1\"}}, expectedArgs: &stringSliceArgs{v: []string{\"arg1\"}}},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"test\", \"-i\"}}, expectedErr: \"flag needs an argument: -i\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(strings.Join(tc.testArgs.v, \" \"), func(t *testing.T) {\n\t\t\tstate := map[string]Args{\"args\": nil}\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:        \"test\",\n\t\t\t\tUsage:       \"this is for testing\",\n\t\t\t\tDescription: \"testing\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tstate[\"args\"] = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tUseShortOptionHandling: true,\n\t\t\t\tWriter:                 io.Discard,\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"abc\", Aliases: []string{\"a\"}},\n\t\t\t\t\t&BoolFlag{Name: \"cde\", Aliases: []string{\"c\"}},\n\t\t\t\t\t&BoolFlag{Name: \"fgh\", Aliases: []string{\"f\"}},\n\t\t\t\t\t&StringFlag{Name: \"ijk\", Aliases: []string{\"i\"}},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), tc.testArgs.Slice())\n\n\t\t\tr := require.New(t)\n\n\t\t\tif tc.expectedErr == \"\" {\n\t\t\t\tr.NoError(err)\n\t\t\t} else {\n\t\t\t\tr.ErrorContains(err, tc.expectedErr)\n\t\t\t}\n\n\t\t\tif tc.expectedArgs == nil {\n\t\t\t\tif state[\"args\"] != nil {\n\t\t\t\t\tr.Len(state[\"args\"].Slice(), 0)\n\t\t\t\t} else {\n\t\t\t\t\tr.Nil(state[\"args\"])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tr.Equal(tc.expectedArgs, state[\"args\"])\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tBefore: func(context.Context, *Command) (context.Context, error) {\n\t\t\treturn nil, fmt.Errorf(\"before error\")\n\t\t},\n\t\tAfter: func(context.Context, *Command) error {\n\t\t\treturn fmt.Errorf(\"after error\")\n\t\t},\n\t\tWriter: io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"bar\"})\n\n\trequire.ErrorContains(t, err, \"before error\")\n\trequire.ErrorContains(t, err, \"after error\")\n}\n\nfunc TestCommand_Run_BeforeSavesMetadata(t *testing.T) {\n\tvar receivedMsgFromAction string\n\tvar receivedMsgFromAfter string\n\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tBefore: func(ctx context.Context, cmd *Command) (context.Context, error) {\n\t\t\tcmd.Metadata[\"msg\"] = \"hello world\"\n\t\t\treturn nil, nil\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\tmsg, ok := cmd.Metadata[\"msg\"]\n\t\t\tif !ok {\n\t\t\t\treturn errors.New(\"msg not found\")\n\t\t\t}\n\t\t\treceivedMsgFromAction = msg.(string)\n\n\t\t\treturn nil\n\t\t},\n\t\tAfter: func(_ context.Context, cmd *Command) error {\n\t\t\tmsg, ok := cmd.Metadata[\"msg\"]\n\t\t\tif !ok {\n\t\t\t\treturn errors.New(\"msg not found\")\n\t\t\t}\n\t\t\treceivedMsgFromAfter = msg.(string)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\"}))\n\trequire.Equal(t, \"hello world\", receivedMsgFromAction)\n\trequire.Equal(t, \"hello world\", receivedMsgFromAfter)\n}\n\nfunc TestCommand_Run_BeforeReturnNewContext(t *testing.T) {\n\tvar receivedValFromAction, receivedValFromAfter string\n\ttype key string\n\n\tbkey := key(\"bkey\")\n\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tBefore: func(ctx context.Context, cmd *Command) (context.Context, error) {\n\t\t\treturn context.WithValue(ctx, bkey, \"bval\"), nil\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\tif val := ctx.Value(bkey); val == nil {\n\t\t\t\treturn errors.New(\"bkey value not found\")\n\t\t\t} else {\n\t\t\t\treceivedValFromAction = val.(string)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t\tAfter: func(ctx context.Context, cmd *Command) error {\n\t\t\tif val := ctx.Value(bkey); val == nil {\n\t\t\t\treturn errors.New(\"bkey value not found\")\n\t\t\t} else {\n\t\t\t\treceivedValFromAfter = val.(string)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\"}))\n\trequire.Equal(t, \"bval\", receivedValFromAfter)\n\trequire.Equal(t, \"bval\", receivedValFromAction)\n}\n\ntype ctxKey string\n\n// ctxCollector is a small helper to collect context values.\ntype ctxCollector struct {\n\t// keys are the keys to check the context for.\n\tkeys []ctxKey\n\n\t// m maps from function name to context name to value.\n\tm map[string]map[ctxKey]string\n}\n\nfunc (cc *ctxCollector) collect(ctx context.Context, fnName string) {\n\tif cc.m == nil {\n\t\tcc.m = make(map[string]map[ctxKey]string)\n\t}\n\n\tif _, ok := cc.m[fnName]; !ok {\n\t\tcc.m[fnName] = make(map[ctxKey]string)\n\t}\n\n\tfor _, k := range cc.keys {\n\t\tif val := ctx.Value(k); val != nil {\n\t\t\tcc.m[fnName][k] = val.(string)\n\t\t}\n\t}\n}\n\nfunc TestCommand_Run_BeforeReturnNewContextSubcommand(t *testing.T) {\n\tbkey := ctxKey(\"bkey\")\n\tbkey2 := ctxKey(\"bkey2\")\n\n\tcc := &ctxCollector{keys: []ctxKey{bkey, bkey2}}\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tBefore: func(ctx context.Context, cmd *Command) (context.Context, error) {\n\t\t\treturn context.WithValue(ctx, bkey, \"bval\"), nil\n\t\t},\n\t\tAfter: func(ctx context.Context, cmd *Command) error {\n\t\t\tcc.collect(ctx, \"bar.After\")\n\t\t\treturn nil\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"baz\",\n\t\t\t\tBefore: func(ctx context.Context, cmd *Command) (context.Context, error) {\n\t\t\t\t\treturn context.WithValue(ctx, bkey2, \"bval2\"), nil\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\t\t\tcc.collect(ctx, \"baz.Action\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tAfter: func(ctx context.Context, cmd *Command) error {\n\t\t\t\t\tcc.collect(ctx, \"baz.After\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"bar\", \"baz\"}))\n\texpected := map[string]map[ctxKey]string{\n\t\t\"bar.After\": {\n\t\t\tbkey:  \"bval\",\n\t\t\tbkey2: \"bval2\",\n\t\t},\n\t\t\"baz.Action\": {\n\t\t\tbkey:  \"bval\",\n\t\t\tbkey2: \"bval2\",\n\t\t},\n\t\t\"baz.After\": {\n\t\t\tbkey:  \"bval\",\n\t\t\tbkey2: \"bval2\",\n\t\t},\n\t}\n\trequire.Equal(t, expected, cc.m)\n}\n\nfunc TestCommand_Run_FlagActionContext(t *testing.T) {\n\tbkey := ctxKey(\"bkey\")\n\tbkey2 := ctxKey(\"bkey2\")\n\n\tcc := &ctxCollector{keys: []ctxKey{bkey, bkey2}}\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tBefore: func(ctx context.Context, cmd *Command) (context.Context, error) {\n\t\t\treturn context.WithValue(ctx, bkey, \"bval\"), nil\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName: \"foo\",\n\t\t\t\tAction: func(ctx context.Context, cmd *Command, _ string) error {\n\t\t\t\t\tcc.collect(ctx, \"bar.foo.Action\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"baz\",\n\t\t\t\tBefore: func(ctx context.Context, cmd *Command) (context.Context, error) {\n\t\t\t\t\treturn context.WithValue(ctx, bkey2, \"bval2\"), nil\n\t\t\t\t},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName: \"goo\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *Command, _ string) error {\n\t\t\t\t\t\t\tcc.collect(ctx, \"baz.goo.Action\")\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"bar\", \"--foo\", \"value\", \"baz\", \"--goo\", \"value\"}))\n\texpected := map[string]map[ctxKey]string{\n\t\t\"bar.foo.Action\": {\n\t\t\tbkey:  \"bval\",\n\t\t\tbkey2: \"bval2\",\n\t\t},\n\t\t\"baz.goo.Action\": {\n\t\t\tbkey:  \"bval\",\n\t\t\tbkey2: \"bval2\",\n\t\t},\n\t}\n\trequire.Equal(t, expected, cc.m)\n}\n\nfunc TestCommand_OnUsageError_hasCommandContext(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"flag\"},\n\t\t},\n\t\tOnUsageError: func(_ context.Context, cmd *Command, err error, _ bool) error {\n\t\t\treturn fmt.Errorf(\"intercepted in %s: %s\", cmd.Name, err.Error())\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"bar\", \"--flag=wrong\"})\n\tassert.ErrorContains(t, err, \"intercepted in bar\")\n}\n\nfunc TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"flag\"},\n\t\t},\n\t\tOnUsageError: func(_ context.Context, _ *Command, err error, _ bool) error {\n\t\t\tassert.ErrorContains(t, err, \"strconv.ParseInt: parsing \\\"wrong\\\"\")\n\t\t\treturn errors.New(\"intercepted: \" + err.Error())\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"bar\", \"--flag=wrong\"})\n\tassert.ErrorContains(t, err, \"intercepted: invalid value \\\"wrong\\\" for flag -flag: strconv.ParseInt: parsing \\\"wrong\\\"\")\n}\n\nfunc TestCommand_OnUsageError_WithSubcommand(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"baz\",\n\t\t\t},\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"flag\"},\n\t\t},\n\t\tOnUsageError: func(_ context.Context, _ *Command, err error, _ bool) error {\n\t\t\tassert.ErrorContains(t, err, \"parsing \\\"wrong\\\": invalid syntax\")\n\t\t\treturn errors.New(\"intercepted: \" + err.Error())\n\t\t},\n\t}\n\n\trequire.ErrorContains(t, cmd.Run(buildTestContext(t), []string{\"bar\", \"--flag=wrong\"}),\n\t\t\"intercepted: invalid value \\\"wrong\\\" for flag -flag: strconv.ParseInt: parsing \\\"wrong\\\": invalid syntax\")\n}\n\nfunc TestCommand_Run_SubcommandsCanUseErrWriter(t *testing.T) {\n\tcmd := &Command{\n\t\tErrWriter: io.Discard,\n\t\tName:      \"bar\",\n\t\tUsage:     \"this is for testing\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:  \"baz\",\n\t\t\t\tUsage: \"this is for testing\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\trequire.Equal(t, io.Discard, cmd.Root().ErrWriter)\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"bar\", \"baz\"}))\n}\n\nfunc TestCommandSkipFlagParsing(t *testing.T) {\n\tcases := []struct {\n\t\ttestArgs     *stringSliceArgs\n\t\texpectedArgs *stringSliceArgs\n\t\texpectedErr  error\n\t}{\n\t\t{testArgs: &stringSliceArgs{v: []string{\"some-command\", \"some-arg\", \"--flag\", \"foo\"}}, expectedArgs: &stringSliceArgs{v: []string{\"some-arg\", \"--flag\", \"foo\"}}, expectedErr: nil},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"some-command\", \"some-arg\", \"--flag=foo\"}}, expectedArgs: &stringSliceArgs{v: []string{\"some-arg\", \"--flag=foo\"}}, expectedErr: nil},\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(strings.Join(c.testArgs.Slice(), \" \"), func(t *testing.T) {\n\t\t\tvar args Args\n\t\t\tcmd := &Command{\n\t\t\t\tSkipFlagParsing: true,\n\t\t\t\tName:            \"some-command\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{Name: \"flag\"},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\targs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), c.testArgs.Slice())\n\t\t\tassert.Equal(t, c.expectedErr, err)\n\t\t\tassert.Equal(t, c.expectedArgs, args)\n\t\t})\n\t}\n}\n\nfunc TestCommand_Run_CustomShellCompleteAcceptsMalformedFlags(t *testing.T) {\n\tcases := []struct {\n\t\ttestArgs    *stringSliceArgs\n\t\texpectedOut string\n\t}{\n\t\t{testArgs: &stringSliceArgs{v: []string{\"--undefined\"}}, expectedOut: \"found 0 args\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"--number\"}}, expectedOut: \"found 0 args\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"--number\", \"forty-two\"}}, expectedOut: \"found 0 args\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"--number\", \"42\"}}, expectedOut: \"found 0 args\"},\n\t\t{testArgs: &stringSliceArgs{v: []string{\"--number\", \"42\", \"newArg\"}}, expectedOut: \"found 1 args\"},\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(strings.Join(c.testArgs.Slice(), \" \"), func(t *testing.T) {\n\t\t\tout := &bytes.Buffer{}\n\t\t\tcmd := &Command{\n\t\t\t\tWriter:                out,\n\t\t\t\tEnableShellCompletion: true,\n\t\t\t\tName:                  \"bar\",\n\t\t\t\tUsage:                 \"this is for testing\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName:  \"number\",\n\t\t\t\t\t\tUsage: \"A number to parse\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tShellComplete: func(_ context.Context, cmd *Command) {\n\t\t\t\t\tfmt.Fprintf(cmd.Root().Writer, \"found %[1]d args\", cmd.NArg())\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tosArgs := &stringSliceArgs{v: []string{\"bar\"}}\n\t\t\tosArgs.v = append(osArgs.v, c.testArgs.Slice()...)\n\t\t\tosArgs.v = append(osArgs.v, completionFlag)\n\n\t\t\tr := require.New(t)\n\n\t\t\tr.NoError(cmd.Run(buildTestContext(t), osArgs.Slice()))\n\t\t\tr.Equal(c.expectedOut, out.String())\n\t\t})\n\t}\n}\n\nfunc TestCommand_CanAddVFlagOnSubCommands(t *testing.T) {\n\tcmd := &Command{\n\t\tVersion: \"some version\",\n\t\tWriter:  io.Discard,\n\t\tName:    \"foo\",\n\t\tUsage:   \"this is for testing\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"bar\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"v\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestCommand_VisibleSubcCommands(t *testing.T) {\n\tsubc1 := &Command{\n\t\tName:  \"subc1\",\n\t\tUsage: \"subc1 command1\",\n\t}\n\tsubc3 := &Command{\n\t\tName:  \"subc3\",\n\t\tUsage: \"subc3 command2\",\n\t}\n\tcmd := &Command{\n\t\tName:  \"bar\",\n\t\tUsage: \"this is for testing\",\n\t\tCommands: []*Command{\n\t\t\tsubc1,\n\t\t\t{\n\t\t\t\tName:   \"subc2\",\n\t\t\t\tUsage:  \"subc2 command2\",\n\t\t\t\tHidden: true,\n\t\t\t},\n\t\t\tsubc3,\n\t\t},\n\t}\n\n\tassert.Equal(t, cmd.VisibleCommands(), []*Command{subc1, subc3})\n}\n\nfunc TestCommand_VisibleFlagCategories(t *testing.T) {\n\tcmd := &Command{\n\t\tName:  \"bar\",\n\t\tUsage: \"this is for testing\",\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName: \"strd\", // no category set\n\t\t\t},\n\t\t\t&StringFlag{\n\t\t\t\tName:   \"strd1\", // no category set and also hidden\n\t\t\t\tHidden: true,\n\t\t\t},\n\t\t\t&Int64Flag{\n\t\t\t\tName:     \"intd\",\n\t\t\t\tAliases:  []string{\"altd1\", \"altd2\"},\n\t\t\t\tCategory: \"cat1\",\n\t\t\t},\n\t\t\t&StringFlag{\n\t\t\t\tName:     \"sfd\",\n\t\t\t\tCategory: \"cat2\", // category set and hidden\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t},\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{{\n\t\t\tCategory: \"cat2\",\n\t\t\tFlags: [][]Flag{\n\t\t\t\t{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName: \"mutex\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}},\n\t}\n\n\tcmd.MutuallyExclusiveFlags[0].propagateCategory()\n\n\tvfc := cmd.VisibleFlagCategories()\n\trequire.Len(t, vfc, 3)\n\n\tassert.Equal(t, vfc[0].Name(), \"\", \"expected category name to be empty\")\n\tassert.Equal(t, vfc[0].Flags()[0].Names(), []string{\"strd\"})\n\n\tassert.Equal(t, vfc[1].Name(), \"cat1\", \"expected category name cat1\")\n\trequire.Len(t, vfc[1].Flags(), 1, \"expected flag category to have one flag\")\n\tassert.Equal(t, vfc[1].Flags()[0].Names(), []string{\"intd\", \"altd1\", \"altd2\"})\n\n\tassert.Equal(t, vfc[2].Name(), \"cat2\", \"expected category name cat2\")\n\trequire.Len(t, vfc[2].Flags(), 1, \"expected flag category to have one flag\")\n\tassert.Equal(t, vfc[2].Flags()[0].Names(), []string{\"mutex\"})\n}\n\nfunc TestCommand_RunSubcommandWithDefault(t *testing.T) {\n\tcmd := &Command{\n\t\tVersion:        \"some version\",\n\t\tName:           \"app\",\n\t\tDefaultCommand: \"foo\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"foo\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn errors.New(\"should not run this subcommand\")\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"bar\",\n\t\t\t\tUsage:    \"this is for testing\",\n\t\t\t\tCommands: []*Command{{}}, // some subcommand\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"app\", \"bar\"})\n\tassert.NoError(t, err)\n\n\terr = cmd.Run(buildTestContext(t), []string{\"app\"})\n\tassert.EqualError(t, err, \"should not run this subcommand\")\n}\n\nfunc TestCommand_Run(t *testing.T) {\n\ts := \"\"\n\n\tcmd := &Command{\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\ts = s + cmd.Args().First()\n\t\t\treturn nil\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"command\", \"foo\"})\n\tassert.NoError(t, err)\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"bar\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, s, \"foobar\")\n}\n\nvar commandTests = []struct {\n\tname     string\n\texpected bool\n}{\n\t{\"foobar\", true},\n\t{\"batbaz\", true},\n\t{\"b\", true},\n\t{\"f\", true},\n\t{\"bat\", false},\n\t{\"nothing\", false},\n}\n\nfunc TestCommand_Command(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{Name: \"foobar\", Aliases: []string{\"f\"}},\n\t\t\t{Name: \"batbaz\", Aliases: []string{\"b\"}},\n\t\t},\n\t}\n\n\tfor _, test := range commandTests {\n\t\tif test.expected {\n\t\t\tassert.NotEmpty(t, cmd.Command(test.name))\n\t\t} else {\n\t\t\tassert.Empty(t, cmd.Command(test.name))\n\t\t}\n\t}\n}\n\nvar defaultCommandTests = []struct {\n\tcmdName        string\n\tdefaultCmd     string\n\targs           []string\n\terrNotExpected bool\n}{\n\t{\"foobar\", \"foobar\", nil, true},\n\t{\"batbaz\", \"foobar\", nil, true},\n\t{\"b\", \"\", nil, true},\n\t{\"f\", \"\", nil, true},\n\t{\"\", \"foobar\", nil, true},\n\t{\"\", \"\", nil, true},\n\t{\" \", \"\", nil, true},\n\t{\"bat\", \"batbaz\", nil, true},\n\t{\"nothing\", \"batbaz\", nil, true},\n\t{\"nothing\", \"\", nil, false},\n\t{\"foobar\", \"foobar\", []string{\"xy\", \"zdf\"}, true},\n\t{\"\", \"foobar\", []string{\"xy\", \"zdf\"}, true},\n}\n\nfunc TestCommand_RunDefaultCommand(t *testing.T) {\n\tfor _, test := range defaultCommandTests {\n\t\ttestTitle := fmt.Sprintf(\"command=%[1]s-default=%[2]s-args=%[3]v\", test.cmdName, test.defaultCmd, test.args)\n\t\tt.Run(testTitle, func(t *testing.T) {\n\t\t\tfooCount := 0\n\t\t\tvar fooArgs Args\n\t\t\tbarCount := 0\n\t\t\tcmd := &Command{\n\t\t\t\tDefaultCommand: test.defaultCmd,\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foobar\",\n\t\t\t\t\t\tAliases: []string{\"f\"},\n\t\t\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\t\t\tfooCount++\n\t\t\t\t\t\t\tfooArgs = c.Args()\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"batbaz\",\n\t\t\t\t\t\tAliases: []string{\"b\"},\n\t\t\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\t\t\tbarCount++\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\trunArgs := []string{\"c\"}\n\t\t\tif test.cmdName != \"\" {\n\t\t\t\trunArgs = append(runArgs, test.cmdName)\n\t\t\t}\n\t\t\tif test.args != nil {\n\t\t\t\trunArgs = append(runArgs, test.args...)\n\t\t\t}\n\t\t\terr := cmd.Run(buildTestContext(t), runArgs)\n\t\t\tif test.errNotExpected {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tif fooCount == 0 && barCount == 0 && test.defaultCmd != \"\" {\n\t\t\t\t\tt.Errorf(\"expected one of the commands to run\")\n\t\t\t\t}\n\t\t\t\tif fooCount > 0 {\n\t\t\t\t\texpectedArgs := &stringSliceArgs{v: []string{}}\n\t\t\t\t\tif len(test.args) > 0 && (test.args[0] == \"foobar\" || test.args[0] == \"f\") {\n\t\t\t\t\t\texpectedArgs = &stringSliceArgs{v: test.args[1:]}\n\t\t\t\t\t} else if test.args != nil {\n\t\t\t\t\t\texpectedArgs = &stringSliceArgs{v: test.args}\n\t\t\t\t\t}\n\t\t\t\t\tassert.Equal(t, expectedArgs, fooArgs)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif fooCount > 0 || barCount > 0 {\n\t\t\t\t\tt.Errorf(\"expected no commands to run\")\n\t\t\t\t}\n\t\t\t\tassert.Error(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nvar defaultCommandSubCommandTests = []struct {\n\tcmdName        string\n\tsubCmd         string\n\tdefaultCmd     string\n\terrNotExpected bool\n}{\n\t{\"foobar\", \"\", \"foobar\", true},\n\t{\"foobar\", \"carly\", \"foobar\", true},\n\t{\"batbaz\", \"\", \"foobar\", true},\n\t{\"b\", \"\", \"\", true},\n\t{\"f\", \"\", \"\", true},\n\t{\"\", \"\", \"foobar\", true},\n\t{\"\", \"\", \"\", true},\n\t{\"\", \"jimbob\", \"foobar\", true},\n\t{\"\", \"j\", \"foobar\", true},\n\t{\"\", \"carly\", \"foobar\", true},\n\t{\"\", \"jimmers\", \"foobar\", false},\n\t{\"\", \"jimmers\", \"\", false},\n\t{\" \", \"jimmers\", \"foobar\", true},\n\t{\"\", \"\", \"\", true},\n\t{\" \", \"\", \"\", true},\n\t{\" \", \"j\", \"\", true},\n\t{\"bat\", \"\", \"batbaz\", false},\n\t{\"nothing\", \"\", \"batbaz\", false},\n\t{\"nothing\", \"\", \"\", false},\n\t{\"nothing\", \"j\", \"batbaz\", false},\n\t{\"nothing\", \"carly\", \"\", false},\n}\n\nfunc TestCommand_RunDefaultCommandWithSubCommand(t *testing.T) {\n\tfor _, test := range defaultCommandSubCommandTests {\n\t\ttestTitle := fmt.Sprintf(\"command=%[1]s-subcmd=%[2]s-default=%[3]s\", test.cmdName, test.subCmd, test.defaultCmd)\n\t\tt.Run(testTitle, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tDefaultCommand: test.defaultCmd,\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foobar\",\n\t\t\t\t\t\tAliases: []string{\"f\"},\n\t\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t\t{Name: \"jimbob\", Aliases: []string{\"j\"}},\n\t\t\t\t\t\t\t{Name: \"carly\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{Name: \"batbaz\", Aliases: []string{\"b\"}},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\trunArgs := []string{\"c\"}\n\t\t\tif test.cmdName != \"\" {\n\t\t\t\trunArgs = append(runArgs, test.cmdName)\n\t\t\t}\n\t\t\tif test.subCmd != \"\" {\n\t\t\t\trunArgs = append(runArgs, test.subCmd)\n\t\t\t}\n\t\t\terr := cmd.Run(buildTestContext(t), runArgs)\n\t\t\tif test.errNotExpected {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Error(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nvar defaultCommandFlagTests = []struct {\n\tcmdName        string\n\tflag           string\n\tdefaultCmd     string\n\terrNotExpected bool\n}{\n\t{\"foobar\", \"\", \"foobar\", true},\n\t{\"foobar\", \"-c derp\", \"foobar\", true},\n\t{\"batbaz\", \"\", \"foobar\", true},\n\t{\"b\", \"\", \"\", true},\n\t{\"f\", \"\", \"\", true},\n\t{\"\", \"\", \"foobar\", true},\n\t{\"\", \"\", \"\", true},\n\t{\"\", \"-j\", \"foobar\", true},\n\t{\"\", \"-j\", \"foobar\", true},\n\t{\"\", \"-c derp\", \"foobar\", true},\n\t{\"\", \"--carly=derp\", \"foobar\", true},\n\t{\"\", \"-j\", \"foobar\", true},\n\t{\"\", \"-j\", \"\", true},\n\t{\" \", \"-j\", \"foobar\", true},\n\t{\"\", \"\", \"\", true},\n\t{\" \", \"\", \"\", true},\n\t{\" \", \"-j\", \"\", true},\n\t{\"bat\", \"\", \"batbaz\", false},\n\t{\"nothing\", \"\", \"batbaz\", false},\n\t{\"nothing\", \"\", \"\", false},\n\t{\"nothing\", \"--jimbob\", \"batbaz\", false},\n\t{\"nothing\", \"--carly\", \"\", false},\n}\n\nfunc TestCommand_RunDefaultCommandWithFlags(t *testing.T) {\n\tfor _, test := range defaultCommandFlagTests {\n\t\ttestTitle := fmt.Sprintf(\"command=%[1]s-flag=%[2]s-default=%[3]s\", test.cmdName, test.flag, test.defaultCmd)\n\t\tt.Run(testTitle, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tDefaultCommand: test.defaultCmd,\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName:     \"carly\",\n\t\t\t\t\t\tAliases:  []string{\"c\"},\n\t\t\t\t\t\tRequired: false,\n\t\t\t\t\t},\n\t\t\t\t\t&BoolFlag{\n\t\t\t\t\t\tName:     \"jimbob\",\n\t\t\t\t\t\tAliases:  []string{\"j\"},\n\t\t\t\t\t\tRequired: false,\n\t\t\t\t\t\tValue:    true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foobar\",\n\t\t\t\t\t\tAliases: []string{\"f\"},\n\t\t\t\t\t},\n\t\t\t\t\t{Name: \"batbaz\", Aliases: []string{\"b\"}},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tappArgs := []string{\"c\"}\n\n\t\t\tif test.flag != \"\" {\n\t\t\t\tflags := strings.Split(test.flag, \" \")\n\t\t\t\tif len(flags) > 1 {\n\t\t\t\t\tappArgs = append(appArgs, flags...)\n\t\t\t\t}\n\n\t\t\t\tflags = strings.Split(test.flag, \"=\")\n\t\t\t\tif len(flags) > 1 {\n\t\t\t\t\tappArgs = append(appArgs, flags...)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tappArgs = append(appArgs, test.cmdName)\n\n\t\t\terr := cmd.Run(buildTestContext(t), appArgs)\n\t\t\tif test.errNotExpected {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Error(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_FlagsFromExtPackage(t *testing.T) {\n\tvar someint int\n\tflag.IntVar(&someint, \"epflag\", 2, \"ext package flag usage\")\n\n\t// Based on source code we can reset the global flag parsing this way\n\tdefer func() {\n\t\tflag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)\n\t}()\n\n\tcmd := &Command{\n\t\tAllowExtFlags: true,\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:     \"carly\",\n\t\t\t\tAliases:  []string{\"c\"},\n\t\t\t\tRequired: false,\n\t\t\t},\n\t\t\t&BoolFlag{\n\t\t\t\tName:     \"jimbob\",\n\t\t\t\tAliases:  []string{\"j\"},\n\t\t\t\tRequired: false,\n\t\t\t\tValue:    true,\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"-c\", \"cly\", \"--epflag\", \"10\"})\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, int(10), someint)\n\t// this exercises the extFlag.Get()\n\tassert.Equal(t, int(10), cmd.Value(\"epflag\"))\n\n\tcmd = &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:     \"carly\",\n\t\t\t\tAliases:  []string{\"c\"},\n\t\t\t\tRequired: false,\n\t\t\t},\n\t\t\t&BoolFlag{\n\t\t\t\tName:     \"jimbob\",\n\t\t\t\tAliases:  []string{\"j\"},\n\t\t\t\tRequired: false,\n\t\t\t\tValue:    true,\n\t\t\t},\n\t\t},\n\t}\n\n\t// this should return an error since epflag shouldnt be registered\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"-c\", \"cly\", \"--epflag\", \"10\"})\n\tassert.Error(t, err)\n}\n\nfunc TestCommand_Setup_defaultsReader(t *testing.T) {\n\tcmd := &Command{}\n\tcmd.setupDefaults([]string{\"test\"})\n\tassert.Equal(t, cmd.Reader, os.Stdin)\n}\n\nfunc TestCommand_Setup_defaultsWriter(t *testing.T) {\n\tcmd := &Command{}\n\tcmd.setupDefaults([]string{\"test\"})\n\tassert.Equal(t, cmd.Writer, os.Stdout)\n}\n\nfunc TestCommand_CommandWithFlagBeforeTerminator(t *testing.T) {\n\tvar parsedOption string\n\tvar args Args\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"cmd\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{Name: \"option\", Value: \"\", Usage: \"some option\"},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tparsedOption = cmd.String(\"option\")\n\t\t\t\t\targs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"--option\", \"my-option\", \"my-arg\", \"--\", \"--notARealFlag\"}))\n\n\trequire.Equal(t, \"my-option\", parsedOption)\n\trequire.Equal(t, \"my-arg\", args.Get(0))\n\trequire.Equal(t, \"--notARealFlag\", args.Get(1))\n}\n\nfunc TestCommand_CommandWithDash(t *testing.T) {\n\tvar args Args\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"cmd\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\targs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"my-arg\", \"-\"}))\n\trequire.NotNil(t, args)\n\trequire.Equal(t, \"my-arg\", args.Get(0))\n\trequire.Equal(t, \"-\", args.Get(1))\n}\n\nfunc TestCommand_CommandWithNoFlagBeforeTerminator(t *testing.T) {\n\tvar args Args\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"cmd\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\targs = cmd.Args()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"my-arg\", \"--\", \"notAFlagAtAll\"}))\n\n\trequire.NotNil(t, args)\n\trequire.Equal(t, \"my-arg\", args.Get(0))\n\trequire.Equal(t, \"notAFlagAtAll\", args.Get(1))\n}\n\nfunc TestCommand_SkipFlagParsing(t *testing.T) {\n\tvar args Args\n\n\tcmd := &Command{\n\t\tSkipFlagParsing: true,\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\targs = cmd.Args()\n\t\t\treturn nil\n\t\t},\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"\", \"--\", \"my-arg\", \"notAFlagAtAll\"})\n\n\tassert.NotNil(t, args)\n\tassert.Equal(t, \"--\", args.Get(0))\n\tassert.Equal(t, \"my-arg\", args.Get(1))\n\tassert.Equal(t, \"notAFlagAtAll\", args.Get(2))\n}\n\nfunc TestCommand_VisibleCommands(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:   \"frob\",\n\t\t\t\tAction: func(context.Context, *Command) error { return nil },\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"frib\",\n\t\t\t\tHidden: true,\n\t\t\t\tAction: func(context.Context, *Command) error { return nil },\n\t\t\t},\n\t\t},\n\t}\n\n\tcmd.setupDefaults([]string{\"test\"})\n\texpected := []*Command{\n\t\tcmd.Commands[0],\n\t}\n\tactual := cmd.VisibleCommands()\n\tassert.Len(t, actual, len(expected))\n\tfor i, actualCommand := range actual {\n\t\texpectedCommand := expected[i]\n\n\t\tif expectedCommand.Action != nil {\n\t\t\t// comparing func addresses is OK!\n\t\t\tassert.Equal(t, fmt.Sprintf(\"%p\", expectedCommand.Action), fmt.Sprintf(\"%p\", actualCommand.Action))\n\t\t}\n\n\t\tfunc() {\n\t\t\t// nil out funcs, as they cannot be compared\n\t\t\t// (https://github.com/golang/go/issues/8554)\n\t\t\texpectedAction := expectedCommand.Action\n\t\t\tactualAction := actualCommand.Action\n\t\t\tdefer func() {\n\t\t\t\texpectedCommand.Action = expectedAction\n\t\t\t\tactualCommand.Action = actualAction\n\t\t\t}()\n\t\t\texpectedCommand.Action = nil\n\t\t\tactualCommand.Action = nil\n\n\t\t\tassert.Equal(t, expectedCommand, actualCommand)\n\t\t}()\n\t}\n}\n\nfunc TestCommand_UseShortOptionHandling(t *testing.T) {\n\tvar one, two bool\n\tvar name string\n\texpected := \"expectedName\"\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcmd.Flags = []Flag{\n\t\t&BoolFlag{Name: \"one\", Aliases: []string{\"o\"}},\n\t\t&BoolFlag{Name: \"two\", Aliases: []string{\"t\"}},\n\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t}\n\tcmd.Action = func(_ context.Context, cmd *Command) error {\n\t\tone = cmd.Bool(\"one\")\n\t\ttwo = cmd.Bool(\"two\")\n\t\tname = cmd.String(\"name\")\n\t\treturn nil\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"\", \"-on\", expected})\n\tassert.True(t, one)\n\tassert.False(t, two)\n\tassert.Equal(t, name, expected)\n}\n\nfunc TestCommand_UseShortOptionHandling_missing_value(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcmd.Flags = []Flag{\n\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"-n\"})\n\tassert.EqualError(t, err, \"flag needs an argument: -n\")\n}\n\nfunc TestCommand_UseShortOptionHandlingCommand(t *testing.T) {\n\tvar (\n\t\tone, two bool\n\t\tname     string\n\t\texpected = \"expectedName\"\n\t)\n\n\tcmd := &Command{\n\t\tName: \"cmd\",\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"one\", Aliases: []string{\"o\"}},\n\t\t\t&BoolFlag{Name: \"two\", Aliases: []string{\"t\"}},\n\t\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tone = cmd.Bool(\"one\")\n\t\t\ttwo = cmd.Bool(\"two\")\n\t\t\tname = cmd.String(\"name\")\n\t\t\treturn nil\n\t\t},\n\t\tUseShortOptionHandling: true,\n\t\tWriter:                 io.Discard,\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"cmd\", \"-on\", expected}))\n\trequire.True(t, one)\n\trequire.False(t, two)\n\trequire.Equal(t, expected, name)\n}\n\nfunc TestCommand_UseShortOptionHandlingCommand_missing_value(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcommand := &Command{\n\t\tName: \"cmd\",\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t\t},\n\t}\n\tcmd.Commands = []*Command{command}\n\n\trequire.EqualError(\n\t\tt,\n\t\tcmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"-n\"}),\n\t\t\"flag needs an argument: -n\",\n\t)\n}\n\nfunc TestCommand_UseShortOptionHandlingSubCommand(t *testing.T) {\n\tvar one, two bool\n\tvar name string\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcmd.Commands = []*Command{\n\t\t{\n\t\t\tName: \"cmd\",\n\t\t\tCommands: []*Command{\n\t\t\t\t{\n\t\t\t\t\tName: \"sub\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"one\", Aliases: []string{\"o\"}},\n\t\t\t\t\t\t&BoolFlag{Name: \"two\", Aliases: []string{\"t\"}},\n\t\t\t\t\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\t\tone = cmd.Bool(\"one\")\n\t\t\t\t\t\ttwo = cmd.Bool(\"two\")\n\t\t\t\t\t\tname = cmd.String(\"name\")\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\texpected := \"expectedName\"\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"sub\", \"-on\", expected}))\n\trequire.True(t, one)\n\trequire.False(t, two)\n\trequire.Equal(t, expected, name)\n}\n\nfunc TestCommand_UseShortOptionHandlingSubCommand_missing_value(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcommand := &Command{\n\t\tName: \"cmd\",\n\t}\n\tsubCommand := &Command{\n\t\tName: \"sub\",\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t\t},\n\t}\n\tcommand.Commands = []*Command{subCommand}\n\tcmd.Commands = []*Command{command}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"sub\", \"-n\"})\n\tassert.EqualError(t, err, \"flag needs an argument: -n\")\n}\n\nfunc TestCommand_UseShortOptionAfterSliceFlag(t *testing.T) {\n\tvar one, two bool\n\tvar name string\n\tvar sliceValDest []string\n\tvar sliceVal []string\n\texpected := \"expectedName\"\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcmd.Flags = []Flag{\n\t\t&StringSliceFlag{Name: \"env\", Aliases: []string{\"e\"}, Destination: &sliceValDest},\n\t\t&BoolFlag{Name: \"one\", Aliases: []string{\"o\"}},\n\t\t&BoolFlag{Name: \"two\", Aliases: []string{\"t\"}},\n\t\t&StringFlag{Name: \"name\", Aliases: []string{\"n\"}},\n\t}\n\tcmd.Action = func(_ context.Context, cmd *Command) error {\n\t\tsliceVal = cmd.StringSlice(\"env\")\n\t\tone = cmd.Bool(\"one\")\n\t\ttwo = cmd.Bool(\"two\")\n\t\tname = cmd.String(\"name\")\n\t\treturn nil\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"\", \"-e\", \"foo\", \"-on\", expected})\n\tassert.Equal(t, sliceVal, []string{\"foo\"})\n\tassert.Equal(t, sliceValDest, []string{\"foo\"})\n\tassert.True(t, one)\n\tassert.False(t, two)\n\tassert.Equal(t, expected, name)\n}\n\nfunc TestCommand_UseShortOptionWithArg(t *testing.T) {\n\tvar rootPath string\n\tcmd := &Command{\n\t\tUseShortOptionHandling: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:  \"short\",\n\t\t\t\tUsage: \"complete a task on the list\",\n\t\t\t\tArguments: []Argument{\n\t\t\t\t\t&StringArg{Name: \"root\", UsageText: \"Root path\", Destination: &rootPath},\n\t\t\t\t},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t\t\t\t&BoolFlag{Name: \"option\", Aliases: []string{\"o\"}},\n\t\t\t\t\t&StringFlag{Name: \"message\", Aliases: []string{\"m\"}},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"app\", \"short\", \"-som\", \"hello\", \"/path/to/root\"})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"/path/to/root\", rootPath)\n}\n\nfunc TestCommand_Float64Flag(t *testing.T) {\n\tvar meters float64\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{Name: \"height\", Value: 1.5, Usage: \"Set the height, in meters\"},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tmeters = cmd.Float(\"height\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"\", \"--height\", \"1.93\"})\n\tassert.Equal(t, 1.93, meters)\n}\n\nfunc TestCommand_ParseSliceFlags(t *testing.T) {\n\tvar parsedIntSlice []int64\n\tvar parsedStringSlice []string\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"cmd\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&Int64SliceFlag{Name: \"p\", Value: []int64{}, Usage: \"set one or more ip addr\"},\n\t\t\t\t\t&StringSliceFlag{Name: \"ip\", Value: []string{}, Usage: \"set one or more ports to open\"},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tparsedIntSlice = cmd.Int64Slice(\"p\")\n\t\t\t\t\tparsedStringSlice = cmd.StringSlice(\"ip\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"-p\", \"22\", \"-p\", \"80\", \"-ip\", \"8.8.8.8\", \"-ip\", \"8.8.4.4\"}))\n\tr.Equal([]int64{22, 80}, parsedIntSlice)\n\tr.Equal([]string{\"8.8.8.8\", \"8.8.4.4\"}, parsedStringSlice)\n}\n\nfunc TestCommand_ParseSliceFlagsWithMissingValue(t *testing.T) {\n\tvar parsedIntSlice []int64\n\tvar parsedStringSlice []string\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"cmd\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&Int64SliceFlag{Name: \"a\", Usage: \"set numbers\"},\n\t\t\t\t\t&StringSliceFlag{Name: \"str\", Usage: \"set strings\"},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tparsedIntSlice = cmd.Int64Slice(\"a\")\n\t\t\t\t\tparsedStringSlice = cmd.StringSlice(\"str\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\", \"cmd\", \"-a\", \"2\", \"-str\", \"A\"}))\n\tr.Equal([]int64{2}, parsedIntSlice)\n\tr.Equal([]string{\"A\"}, parsedStringSlice)\n}\n\nfunc TestCommand_DefaultStdin(t *testing.T) {\n\tcmd := &Command{}\n\tcmd.setupDefaults([]string{\"test\"})\n\n\tassert.Equal(t, cmd.Reader, os.Stdin, \"Default input reader not set.\")\n}\n\nfunc TestCommand_DefaultStdout(t *testing.T) {\n\tcmd := &Command{}\n\tcmd.setupDefaults([]string{\"test\"})\n\n\tassert.Equal(t, cmd.Writer, os.Stdout, \"Default output writer not set.\")\n}\n\nfunc TestCommand_SetStdin(t *testing.T) {\n\tbuf := make([]byte, 12)\n\n\tcmd := &Command{\n\t\tName:   \"test\",\n\t\tReader: strings.NewReader(\"Hello World!\"),\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t_, err := cmd.Reader.Read(buf)\n\t\t\treturn err\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"help\"})\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"Hello World!\", string(buf), \"Command did not read input from desired reader.\")\n}\n\nfunc TestCommand_SetStdin_Subcommand(t *testing.T) {\n\tbuf := make([]byte, 12)\n\n\tcmd := &Command{\n\t\tName:   \"test\",\n\t\tReader: strings.NewReader(\"Hello World!\"),\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"command\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"subcommand\",\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\t\t\t_, err := cmd.Root().Reader.Read(buf)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"test\", \"command\", \"subcommand\"})\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"Hello World!\", string(buf), \"Command did not read input from desired reader.\")\n}\n\nfunc TestCommand_SetStdout(t *testing.T) {\n\tvar w bytes.Buffer\n\n\tcmd := &Command{\n\t\tName:   \"test\",\n\t\tWriter: &w,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"help\"})\n\trequire.NoError(t, err)\n\tassert.NotZero(t, w.Len(), \"Command did not write output to desired writer.\")\n}\n\nfunc TestCommand_BeforeFunc(t *testing.T) {\n\tcounts := &opCounts{}\n\tbeforeError := fmt.Errorf(\"fail\")\n\tvar err error\n\n\tcmd := &Command{\n\t\tBefore: func(_ context.Context, cmd *Command) (context.Context, error) {\n\t\t\tcounts.Total++\n\t\t\tcounts.Before = counts.Total\n\t\t\ts := cmd.String(\"opt\")\n\t\t\tif s == \"fail\" {\n\t\t\t\treturn nil, beforeError\n\t\t\t}\n\n\t\t\treturn nil, nil\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tcounts.Total++\n\t\t\t\t\tcounts.SubCommand = counts.Total\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"opt\"},\n\t\t},\n\t\tWriter: io.Discard,\n\t}\n\n\t// run with the Before() func succeeding\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"--opt\", \"succeed\", \"sub\"})\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, 1, counts.Before, \"Before() not executed when expected\")\n\tassert.Equal(t, 2, counts.SubCommand, \"Subcommand not executed when expected\")\n\n\t// reset\n\tcounts = &opCounts{}\n\n\t// run with the Before() func failing\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"--opt\", \"fail\", \"sub\"})\n\n\t// should be the same error produced by the Before func\n\tassert.ErrorIs(t, err, beforeError, \"Run error expected, but not received\")\n\tassert.Equal(t, 1, counts.Before, \"Before() not executed when expected\")\n\tassert.Equal(t, 0, counts.SubCommand, \"Subcommand executed when NOT expected\")\n\n\t// reset\n\tcounts = &opCounts{}\n\n\tafterError := errors.New(\"fail again\")\n\tcmd.After = func(context.Context, *Command) error {\n\t\treturn afterError\n\t}\n\n\t// run with the Before() func failing, wrapped by After()\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"--opt\", \"fail\", \"sub\"})\n\n\t// should be the same error produced by the Before func\n\tif _, ok := err.(MultiError); !ok {\n\t\tt.Errorf(\"MultiError expected, but not received\")\n\t}\n\n\tassert.Equal(t, 1, counts.Before, \"Before() not executed when expected\")\n\tassert.Zero(t, counts.SubCommand, \"Subcommand executed when NOT expected\")\n}\n\nfunc TestCommand_BeforeFuncPersistentFlag(t *testing.T) {\n\tcounts := &opCounts{}\n\tbeforeError := fmt.Errorf(\"fail\")\n\tvar err error\n\n\tcmd := &Command{\n\t\tBefore: func(_ context.Context, cmd *Command) (context.Context, error) {\n\t\t\tcounts.Before++\n\t\t\ts := cmd.String(\"opt\")\n\t\t\tif s != \"value\" {\n\t\t\t\treturn nil, beforeError\n\t\t\t}\n\t\t\treturn nil, nil\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tcounts.SubCommand++\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"opt\"},\n\t\t},\n\t\tWriter: io.Discard,\n\t}\n\n\t// Check that --opt value is available in root command Before hook,\n\t// even when it was set on the subcommand.\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"sub\", \"--opt\", \"value\"})\n\trequire.NoError(t, err)\n\tassert.Equal(t, 1, counts.Before, \"Before() not executed when expected\")\n\tassert.Equal(t, 1, counts.SubCommand, \"Subcommand not executed when expected\")\n}\n\nfunc TestCommand_BeforeAfterFuncShellCompletion(t *testing.T) {\n\tt.Skip(\"TODO: is '--generate-shell-completion' (flag) still supported?\")\n\n\tcounts := &opCounts{}\n\n\tcmd := &Command{\n\t\tEnableShellCompletion: true,\n\t\tBefore: func(context.Context, *Command) (context.Context, error) {\n\t\t\tcounts.Total++\n\t\t\tcounts.Before = counts.Total\n\t\t\treturn nil, nil\n\t\t},\n\t\tAfter: func(context.Context, *Command) error {\n\t\t\tcounts.Total++\n\t\t\tcounts.After = counts.Total\n\t\t\treturn nil\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tcounts.Total++\n\t\t\t\t\tcounts.SubCommand = counts.Total\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"opt\"},\n\t\t},\n\t\tWriter: io.Discard,\n\t}\n\n\tr := require.New(t)\n\n\t// run with the Before() func succeeding\n\tr.NoError(\n\t\tcmd.Run(\n\t\t\tbuildTestContext(t),\n\t\t\t[]string{\n\t\t\t\t\"command\",\n\t\t\t\t\"--opt\", \"succeed\",\n\t\t\t\t\"sub\", completionFlag,\n\t\t\t},\n\t\t),\n\t)\n\n\tr.Equalf(0, counts.Before, \"Before was run\")\n\tr.Equal(0, counts.After, \"After was run\")\n\tr.Equal(0, counts.SubCommand, \"SubCommand was run\")\n}\n\nfunc TestCommand_AfterFunc(t *testing.T) {\n\tcounts := &opCounts{}\n\tafterError := fmt.Errorf(\"fail\")\n\tvar err error\n\n\tcmd := &Command{\n\t\tAfter: func(_ context.Context, cmd *Command) error {\n\t\t\tcounts.Total++\n\t\t\tcounts.After = counts.Total\n\t\t\ts := cmd.String(\"opt\")\n\t\t\tif s == \"fail\" {\n\t\t\t\treturn afterError\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tcounts.Total++\n\t\t\t\t\tcounts.SubCommand = counts.Total\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"opt\"},\n\t\t},\n\t}\n\n\t// run with the After() func succeeding\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"--opt\", \"succeed\", \"sub\"})\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, counts.After, \"After() not executed when expected\")\n\tassert.Equal(t, 1, counts.SubCommand, \"Subcommand not executed when expected\")\n\n\t// reset\n\tcounts = &opCounts{}\n\n\t// run with the Before() func failing\n\terr = cmd.Run(buildTestContext(t), []string{\"command\", \"--opt\", \"fail\", \"sub\"})\n\n\t// should be the same error produced by the Before func\n\tassert.ErrorIs(t, err, afterError, \"Run error expected, but not received\")\n\tassert.Equal(t, 2, counts.After, \"After() not executed when expected\")\n\tassert.Equal(t, 1, counts.SubCommand, \"Subcommand not executed when expected\")\n\n\t/*\n\t\treset\n\t*/\n\tcounts = &opCounts{}\n\t// reset the flags since they are set previously\n\tcmd.Flags = []Flag{\n\t\t&StringFlag{Name: \"opt\"},\n\t}\n\n\t// run with none args\n\terr = cmd.Run(buildTestContext(t), []string{\"command\"})\n\n\t// should be the same error produced by the Before func\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, 1, counts.After, \"After() not executed when expected\")\n\tassert.Equal(t, 0, counts.SubCommand, \"Subcommand not executed when expected\")\n}\n\nfunc TestCommandNoHelpFlag(t *testing.T) {\n\toldFlag := HelpFlag\n\tdefer func() {\n\t\tHelpFlag = oldFlag\n\t}()\n\n\tHelpFlag = nil\n\n\tcmd := &Command{Writer: io.Discard}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"test\", \"-h\"})\n\n\tassert.ErrorContains(t, err, providedButNotDefinedErrMsg, \"expected error about missing help flag\")\n}\n\nfunc TestRequiredFlagCommandRunBehavior(t *testing.T) {\n\ttdata := []struct {\n\t\ttestCase        string\n\t\tappFlags        []Flag\n\t\tappRunInput     []string\n\t\tappCommands     []*Command\n\t\texpectedAnError bool\n\t}{\n\t\t// assertion: empty input, when a required flag is present, errors\n\t\t{\n\t\t\ttestCase:        \"error_case_empty_input_with_required_flag_on_app\",\n\t\t\tappRunInput:     []string{\"myCLI\"},\n\t\t\tappFlags:        []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"error_case_empty_input_with_required_flag_on_command\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName:  \"myCommand\",\n\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\t}},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"error_case_empty_input_with_required_flag_on_subcommand\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"mySubCommand\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName: \"myCommand\",\n\t\t\t\tCommands: []*Command{{\n\t\t\t\t\tName:  \"mySubCommand\",\n\t\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\t\t}},\n\t\t\t}},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t// assertion: inputting --help, when a required flag is present, does not error\n\t\t{\n\t\t\ttestCase:    \"valid_case_help_input_with_required_flag_on_app\",\n\t\t\tappRunInput: []string{\"myCLI\", \"--help\"},\n\t\t\tappFlags:    []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"valid_case_help_input_with_required_flag_on_command\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"--help\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName:  \"myCommand\",\n\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"valid_case_help_input_with_required_flag_on_subcommand\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"mySubCommand\", \"--help\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName: \"myCommand\",\n\t\t\t\tCommands: []*Command{{\n\t\t\t\t\tName:  \"mySubCommand\",\n\t\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\t\t}},\n\t\t\t}},\n\t\t},\n\t\t// assertion: giving optional input, when a required flag is present, errors\n\t\t{\n\t\t\ttestCase:        \"error_case_optional_input_with_required_flag_on_app\",\n\t\t\tappRunInput:     []string{\"myCLI\", \"--optional\", \"cats\"},\n\t\t\tappFlags:        []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}, &StringFlag{Name: \"optional\"}},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"error_case_optional_input_with_required_flag_on_command\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"--optional\", \"cats\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName:  \"myCommand\",\n\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}, &StringFlag{Name: \"optional\"}},\n\t\t\t}},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"error_case_optional_input_with_required_flag_on_subcommand\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"mySubCommand\", \"--optional\", \"cats\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName: \"myCommand\",\n\t\t\t\tCommands: []*Command{{\n\t\t\t\t\tName:  \"mySubCommand\",\n\t\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}, &StringFlag{Name: \"optional\"}},\n\t\t\t\t}},\n\t\t\t}},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t// assertion: when a required flag is present, inputting that required flag does not error\n\t\t{\n\t\t\ttestCase:    \"valid_case_required_flag_input_on_app\",\n\t\t\tappRunInput: []string{\"myCLI\", \"--requiredFlag\", \"cats\"},\n\t\t\tappFlags:    []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"valid_case_required_flag_input_on_command\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"--requiredFlag\", \"cats\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName:  \"myCommand\",\n\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\ttestCase:    \"valid_case_required_flag_input_on_subcommand\",\n\t\t\tappRunInput: []string{\"myCLI\", \"myCommand\", \"mySubCommand\", \"--requiredFlag\", \"cats\"},\n\t\t\tappCommands: []*Command{{\n\t\t\t\tName: \"myCommand\",\n\t\t\t\tCommands: []*Command{{\n\t\t\t\t\tName:  \"mySubCommand\",\n\t\t\t\t\tFlags: []Flag{&StringFlag{Name: \"requiredFlag\", Required: true}},\n\t\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t}},\n\t\t\t}},\n\t\t},\n\t}\n\tfor _, test := range tdata {\n\t\tt.Run(test.testCase, func(t *testing.T) {\n\t\t\t// setup\n\t\t\tcmd := buildMinimalTestCommand()\n\t\t\tcmd.Flags = test.appFlags\n\t\t\tcmd.Commands = test.appCommands\n\n\t\t\t// logic under test\n\t\t\terr := cmd.Run(buildTestContext(t), test.appRunInput)\n\n\t\t\t// assertions\n\t\t\tif test.expectedAnError {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tif _, ok := err.(requiredFlagsErr); test.expectedAnError && !ok {\n\t\t\t\t\tt.Errorf(\"expected a requiredFlagsErr, but got: %s\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommandHelpPrinter(t *testing.T) {\n\toldPrinter := HelpPrinter\n\tdefer func() {\n\t\tHelpPrinter = oldPrinter\n\t}()\n\n\twasCalled := false\n\tHelpPrinter = func(io.Writer, string, interface{}) {\n\t\twasCalled = true\n\t}\n\n\tcmd := &Command{}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"-h\"})\n\n\tassert.True(t, wasCalled, \"Help printer expected to be called, but was not\")\n}\n\nfunc TestCommand_VersionPrinter(t *testing.T) {\n\toldPrinter := VersionPrinter\n\tdefer func() {\n\t\tVersionPrinter = oldPrinter\n\t}()\n\n\twasCalled := false\n\tVersionPrinter = func(*Command) {\n\t\twasCalled = true\n\t}\n\n\tcmd := &Command{}\n\tShowVersion(cmd)\n\n\tassert.True(t, wasCalled, \"Version printer expected to be called, but was not\")\n}\n\nfunc TestCommand_CommandNotFound(t *testing.T) {\n\tcounts := &opCounts{}\n\tcmd := &Command{\n\t\tCommandNotFound: func(context.Context, *Command, string) {\n\t\t\tcounts.Total++\n\t\t\tcounts.CommandNotFound = counts.Total\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"bar\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tcounts.Total++\n\t\t\t\t\tcounts.SubCommand = counts.Total\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"command\", \"foo\"})\n\n\tassert.Equal(t, 1, counts.CommandNotFound)\n\tassert.Equal(t, 0, counts.SubCommand)\n\tassert.Equal(t, 1, counts.Total)\n}\n\nfunc TestCommand_OrderOfOperations(t *testing.T) {\n\tbuildCmdCounts := func() (*Command, *opCounts) {\n\t\tcounts := &opCounts{}\n\n\t\tcmd := &Command{\n\t\t\tEnableShellCompletion: true,\n\t\t\tShellComplete: func(context.Context, *Command) {\n\t\t\t\tcounts.Total++\n\t\t\t\tcounts.ShellComplete = counts.Total\n\t\t\t},\n\t\t\tOnUsageError: func(context.Context, *Command, error, bool) error {\n\t\t\t\tcounts.Total++\n\t\t\t\tcounts.OnUsageError = counts.Total\n\t\t\t\treturn errors.New(\"hay OnUsageError\")\n\t\t\t},\n\t\t\tWriter: io.Discard,\n\t\t}\n\n\t\tbeforeNoError := func(context.Context, *Command) (context.Context, error) {\n\t\t\tcounts.Total++\n\t\t\tcounts.Before = counts.Total\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tcmd.Before = beforeNoError\n\t\tcmd.CommandNotFound = func(context.Context, *Command, string) {\n\t\t\tcounts.Total++\n\t\t\tcounts.CommandNotFound = counts.Total\n\t\t}\n\n\t\tafterNoError := func(context.Context, *Command) error {\n\t\t\tcounts.Total++\n\t\t\tcounts.After = counts.Total\n\t\t\treturn nil\n\t\t}\n\n\t\tcmd.After = afterNoError\n\t\tcmd.Commands = []*Command{\n\t\t\t{\n\t\t\t\tName: \"bar\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tcounts.Total++\n\t\t\t\t\tcounts.SubCommand = counts.Total\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tcmd.Action = func(context.Context, *Command) error {\n\t\t\tcounts.Total++\n\t\t\tcounts.Action = counts.Total\n\t\t\treturn nil\n\t\t}\n\n\t\treturn cmd, counts\n\t}\n\n\tt.Run(\"on usage error\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tr := require.New(t)\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\", \"--nope\"})\n\t\tr.Equal(1, counts.OnUsageError)\n\t\tr.Equal(1, counts.Total)\n\t})\n\n\tt.Run(\"shell complete\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tr := require.New(t)\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\", completionFlag})\n\t\tr.Equal(1, counts.ShellComplete)\n\t\tr.Equal(1, counts.Total)\n\t})\n\n\tt.Run(\"nil on usage error\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tcmd.OnUsageError = nil\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\", \"--nope\"})\n\t\trequire.Equal(t, 0, counts.Total)\n\t})\n\n\tt.Run(\"before after action hooks\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tr := require.New(t)\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\", \"foo\"})\n\t\tr.Equal(0, counts.OnUsageError)\n\t\tr.Equal(1, counts.Before)\n\t\tr.Equal(0, counts.CommandNotFound)\n\t\tr.Equal(2, counts.Action)\n\t\tr.Equal(3, counts.After)\n\t\tr.Equal(3, counts.Total)\n\t})\n\n\tt.Run(\"before with error\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tcmd.Before = func(context.Context, *Command) (context.Context, error) {\n\t\t\tcounts.Total++\n\t\t\tcounts.Before = counts.Total\n\t\t\treturn nil, errors.New(\"hay Before\")\n\t\t}\n\n\t\tr := require.New(t)\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\", \"bar\"})\n\t\tr.Equal(0, counts.OnUsageError)\n\t\tr.Equal(1, counts.Before)\n\t\tr.Equal(2, counts.After)\n\t\tr.Equal(2, counts.Total)\n\t})\n\n\tt.Run(\"nil after\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tcmd.After = nil\n\t\tr := require.New(t)\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\", \"bar\"})\n\t\tr.Equal(0, counts.OnUsageError)\n\t\tr.Equal(1, counts.Before)\n\t\tr.Equal(2, counts.SubCommand)\n\t\tr.Equal(2, counts.Total)\n\t})\n\n\tt.Run(\"after errors\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tcmd.After = func(context.Context, *Command) error {\n\t\t\tcounts.Total++\n\t\t\tcounts.After = counts.Total\n\t\t\treturn errors.New(\"hay After\")\n\t\t}\n\n\t\tr := require.New(t)\n\n\t\terr := cmd.Run(buildTestContext(t), []string{\"command\", \"bar\"})\n\t\tr.Error(err)\n\t\tr.Equal(0, counts.OnUsageError)\n\t\tr.Equal(1, counts.Before)\n\t\tr.Equal(2, counts.SubCommand)\n\t\tr.Equal(3, counts.After)\n\t\tr.Equal(3, counts.Total)\n\t})\n\n\tt.Run(\"nil commands\", func(t *testing.T) {\n\t\tcmd, counts := buildCmdCounts()\n\t\tcmd.Commands = nil\n\t\tr := require.New(t)\n\n\t\t_ = cmd.Run(buildTestContext(t), []string{\"command\"})\n\t\tr.Equal(0, counts.OnUsageError)\n\t\tr.Equal(1, counts.Before)\n\t\tr.Equal(2, counts.Action)\n\t\tr.Equal(3, counts.After)\n\t\tr.Equal(3, counts.Total)\n\t})\n}\n\nfunc TestCommand_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {\n\tsubcommandHelpTopics := [][]string{\n\t\t{\"foo\", \"--help\"},\n\t\t{\"foo\", \"-h\"},\n\t\t{\"foo\", \"help\"},\n\t}\n\n\tfor _, flagSet := range subcommandHelpTopics {\n\t\tt.Run(fmt.Sprintf(\"checking with flags %v\", flagSet), func(t *testing.T) {\n\t\t\tbuf := new(bytes.Buffer)\n\n\t\t\tsubCmdBar := &Command{\n\t\t\t\tName:  \"bar\",\n\t\t\t\tUsage: \"does bar things\",\n\t\t\t}\n\t\t\tsubCmdBaz := &Command{\n\t\t\t\tName:  \"baz\",\n\t\t\t\tUsage: \"does baz things\",\n\t\t\t}\n\t\t\tcmd := &Command{\n\t\t\t\tName:        \"foo\",\n\t\t\t\tDescription: \"descriptive wall of text about how it does foo things\",\n\t\t\t\tCommands:    []*Command{subCmdBar, subCmdBaz},\n\t\t\t\tAction:      func(context.Context, *Command) error { return nil },\n\t\t\t\tWriter:      buf,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), flagSet)\n\t\t\tassert.NoError(t, err)\n\n\t\t\toutput := buf.String()\n\n\t\t\tassert.NotContains(t, output, \"No help topic for\", \"expect a help topic, got none\")\n\n\t\t\tfor _, shouldContain := range []string{\n\t\t\t\tcmd.Name, cmd.Description,\n\t\t\t\tsubCmdBar.Name, subCmdBar.Usage,\n\t\t\t\tsubCmdBaz.Name, subCmdBaz.Usage,\n\t\t\t} {\n\t\t\t\tassert.Contains(t, output, shouldContain, \"want help to contain %q, did not: \\n%q\", shouldContain, output)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Run_SubcommandFullPath(t *testing.T) {\n\tout := &bytes.Buffer{}\n\n\tsubCmd := &Command{\n\t\tName:      \"bar\",\n\t\tUsage:     \"does bar things\",\n\t\tArgsUsage: \"[arguments...]\",\n\t}\n\n\tcmd := &Command{\n\t\tName:        \"foo\",\n\t\tDescription: \"foo commands\",\n\t\tCommands:    []*Command{subCmd},\n\t\tWriter:      out,\n\t}\n\n\trequire.NoError(t, cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\", \"--help\"}))\n\n\toutString := out.String()\n\trequire.Contains(t, outString, \"foo bar - does bar things\")\n\trequire.Contains(t, outString, \"foo bar [options] [arguments...]\")\n}\n\nfunc TestCommand_Run_Help(t *testing.T) {\n\ttests := []struct {\n\t\thelpArguments []string\n\t\thideHelp      bool\n\t\twantContains  string\n\t\twantErr       error\n\t}{\n\t\t{\n\t\t\thelpArguments: []string{\"boom\", \"--help\"},\n\t\t\thideHelp:      false,\n\t\t\twantContains:  \"boom - make an explosive entrance\",\n\t\t},\n\t\t{\n\t\t\thelpArguments: []string{\"boom\", \"-h\"},\n\t\t\thideHelp:      false,\n\t\t\twantContains:  \"boom - make an explosive entrance\",\n\t\t},\n\t\t{\n\t\t\thelpArguments: []string{\"boom\", \"help\"},\n\t\t\thideHelp:      false,\n\t\t\twantContains:  \"boom - make an explosive entrance\",\n\t\t},\n\t\t{\n\t\t\thelpArguments: []string{\"boom\", \"--help\"},\n\t\t\thideHelp:      true,\n\t\t\twantErr:       fmt.Errorf(\"flag provided but not defined: -help\"),\n\t\t},\n\t\t{\n\t\t\thelpArguments: []string{\"boom\", \"-h\"},\n\t\t\thideHelp:      true,\n\t\t\twantErr:       fmt.Errorf(\"flag provided but not defined: -h\"),\n\t\t},\n\t\t{\n\t\t\thelpArguments: []string{\"boom\", \"help\"},\n\t\t\thideHelp:      true,\n\t\t\twantContains:  \"boom I say!\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(fmt.Sprintf(\"checking with arguments %v%v\", tt.helpArguments, tt.hideHelp), func(t *testing.T) {\n\t\t\tbuf := new(bytes.Buffer)\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:     \"boom\",\n\t\t\t\tUsage:    \"make an explosive entrance\",\n\t\t\t\tWriter:   buf,\n\t\t\t\tHideHelp: tt.hideHelp,\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tbuf.WriteString(\"boom I say!\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), tt.helpArguments)\n\t\t\tif tt.wantErr != nil {\n\t\t\t\tassert.ErrorContains(t, err, tt.wantErr.Error())\n\t\t\t}\n\n\t\t\toutput := buf.String()\n\n\t\t\tassert.Contains(t, output, tt.wantContains, \"want help to contain %q, did not: \\n%q\", \"boom - make an explosive entrance\", output)\n\t\t})\n\t}\n}\n\nfunc TestCommand_Run_Version(t *testing.T) {\n\tversionArguments := [][]string{{\"boom\", \"--version\"}, {\"boom\", \"-v\"}}\n\n\tfor _, args := range versionArguments {\n\t\tt.Run(fmt.Sprintf(\"checking with arguments %v\", args), func(t *testing.T) {\n\t\t\tbuf := new(bytes.Buffer)\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:    \"boom\",\n\t\t\t\tUsage:   \"make an explosive entrance\",\n\t\t\t\tVersion: \"0.1.0\",\n\t\t\t\tWriter:  buf,\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\tbuf.WriteString(\"boom I say!\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), args)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Contains(t, buf.String(), \"0.1.0\", \"want version to contain 0.1.0\")\n\t\t})\n\t}\n}\n\nfunc TestCommand_Run_Categories(t *testing.T) {\n\tbuf := new(bytes.Buffer)\n\n\tcmd := &Command{\n\t\tName:     \"categories\",\n\t\tHideHelp: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:     \"command1\",\n\t\t\t\tCategory: \"1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command2\",\n\t\t\t\tCategory: \"1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command3\",\n\t\t\t\tCategory: \"2\",\n\t\t\t},\n\t\t},\n\t\tWriter: buf,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"categories\"})\n\n\texpect := commandCategories([]*commandCategory{\n\t\t{\n\t\t\tname: \"1\",\n\t\t\tcommands: []*Command{\n\t\t\t\tcmd.Commands[0],\n\t\t\t\tcmd.Commands[1],\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"2\",\n\t\t\tcommands: []*Command{\n\t\t\t\tcmd.Commands[2],\n\t\t\t},\n\t\t},\n\t})\n\n\trequire.Equal(t, &expect, cmd.categories)\n\n\toutput := buf.String()\n\n\tassert.Contains(t, output, \"1:\\n     command1\", \"want buffer to include category %q, did not: \\n%q\", \"1:\\n     command1\", output)\n}\n\nfunc TestCommand_VisibleCategories(t *testing.T) {\n\tcmd := &Command{\n\t\tName:     \"visible-categories\",\n\t\tHideHelp: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:     \"command1\",\n\t\t\t\tCategory: \"1\",\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command2\",\n\t\t\t\tCategory: \"2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command3\",\n\t\t\t\tCategory: \"3\",\n\t\t\t},\n\t\t},\n\t}\n\n\texpected := []CommandCategory{\n\t\t&commandCategory{\n\t\t\tname: \"2\",\n\t\t\tcommands: []*Command{\n\t\t\t\tcmd.Commands[1],\n\t\t\t},\n\t\t},\n\t\t&commandCategory{\n\t\t\tname: \"3\",\n\t\t\tcommands: []*Command{\n\t\t\t\tcmd.Commands[2],\n\t\t\t},\n\t\t},\n\t}\n\n\tcmd.setupDefaults([]string{\"test\"})\n\tassert.Equal(t, expected, cmd.VisibleCategories())\n\n\tcmd = &Command{\n\t\tName:     \"visible-categories\",\n\t\tHideHelp: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:     \"command1\",\n\t\t\t\tCategory: \"1\",\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command2\",\n\t\t\t\tCategory: \"2\",\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command3\",\n\t\t\t\tCategory: \"3\",\n\t\t\t},\n\t\t},\n\t}\n\n\texpected = []CommandCategory{\n\t\t&commandCategory{\n\t\t\tname: \"3\",\n\t\t\tcommands: []*Command{\n\t\t\t\tcmd.Commands[2],\n\t\t\t},\n\t\t},\n\t}\n\n\tcmd.setupDefaults([]string{\"test\"})\n\tassert.Equal(t, expected, cmd.VisibleCategories())\n\n\tcmd = &Command{\n\t\tName:     \"visible-categories\",\n\t\tHideHelp: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:     \"command1\",\n\t\t\t\tCategory: \"1\",\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command2\",\n\t\t\t\tCategory: \"2\",\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"command3\",\n\t\t\t\tCategory: \"3\",\n\t\t\t\tHidden:   true,\n\t\t\t},\n\t\t},\n\t}\n\n\tcmd.setupDefaults([]string{\"test\"})\n\tassert.Empty(t, cmd.VisibleCategories())\n}\n\nfunc TestCommand_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"sub\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tName:   \"bar\",\n\t\t\t\tBefore: func(context.Context, *Command) (context.Context, error) { return nil, fmt.Errorf(\"before error\") },\n\t\t\t\tAfter:  func(context.Context, *Command) error { return fmt.Errorf(\"after error\") },\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\"})\n\tassert.ErrorContains(t, err, \"before error\")\n\tassert.ErrorContains(t, err, \"after error\")\n}\n\nfunc TestCommand_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"flag\"},\n\t\t},\n\t\tOnUsageError: func(_ context.Context, _ *Command, err error, isSubcommand bool) error {\n\t\t\tassert.False(t, isSubcommand, \"Expect subcommand\")\n\t\t\tassert.ErrorContains(t, err, \"\\\"wrong\\\": invalid syntax\")\n\t\t\treturn errors.New(\"intercepted: \" + err.Error())\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"bar\",\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--flag=wrong\", \"bar\"})\n\tassert.ErrorContains(t, err, \"parsing \\\"wrong\\\": invalid syntax\", \"Expect an intercepted error\")\n}\n\n// A custom flag that conforms to the relevant interfaces, but has none of the\n// fields that the other flag types do.\ntype customBoolFlag struct {\n\tNombre string\n}\n\n// Don't use the normal FlagStringer\nfunc (c *customBoolFlag) String() string {\n\treturn \"***\" + c.Nombre + \"***\"\n}\n\nfunc (c *customBoolFlag) Names() []string {\n\treturn []string{c.Nombre}\n}\n\nfunc (c *customBoolFlag) TakesValue() bool {\n\treturn false\n}\n\nfunc (c *customBoolFlag) GetValue() string {\n\treturn \"value\"\n}\n\nfunc (c *customBoolFlag) GetUsage() string {\n\treturn \"usage\"\n}\n\nfunc (c *customBoolFlag) PreParse() error {\n\treturn nil\n}\n\nfunc (c *customBoolFlag) PostParse() error {\n\treturn nil\n}\n\nfunc (c *customBoolFlag) Get() any {\n\tdest := false\n\treturn &boolValue{\n\t\tdestination: &dest,\n\t}\n}\n\nfunc (c *customBoolFlag) Set(_, _ string) error {\n\treturn nil\n}\n\nfunc (c *customBoolFlag) RunAction(context.Context, *Command) error {\n\treturn nil\n}\n\nfunc (c *customBoolFlag) IsSet() bool {\n\treturn false\n}\n\nfunc (c *customBoolFlag) IsRequired() bool {\n\treturn false\n}\n\nfunc (c *customBoolFlag) IsVisible() bool {\n\treturn false\n}\n\nfunc (c *customBoolFlag) GetCategory() string {\n\treturn \"\"\n}\n\nfunc (c *customBoolFlag) GetEnvVars() []string {\n\treturn nil\n}\n\nfunc (c *customBoolFlag) GetDefaultText() string {\n\treturn \"\"\n}\n\nfunc TestCustomFlagsUnused(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags:  []Flag{&customBoolFlag{\"custom\"}},\n\t\tWriter: io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\"})\n\tassert.NoError(t, err, \"Run returned unexpected error\")\n}\n\nfunc TestCustomFlagsUsed(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags:  []Flag{&customBoolFlag{\"custom\"}},\n\t\tWriter: io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--custom=bar\"})\n\tassert.NoError(t, err, \"Run returned unexpected error\")\n}\n\nfunc TestCustomHelpVersionFlags(t *testing.T) {\n\tcmd := &Command{\n\t\tWriter: io.Discard,\n\t}\n\n\t// Be sure to reset the global flags\n\tdefer func(helpFlag Flag, versionFlag Flag) {\n\t\tHelpFlag = helpFlag.(*BoolFlag)\n\t\tVersionFlag = versionFlag.(*BoolFlag)\n\t}(HelpFlag, VersionFlag)\n\n\tHelpFlag = &customBoolFlag{\"help-custom\"}\n\tVersionFlag = &customBoolFlag{\"version-custom\"}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--help-custom=bar\"})\n\tassert.NoError(t, err, \"Run returned unexpected error\")\n}\n\nfunc TestHandleExitCoder_Default(t *testing.T) {\n\tapp := buildMinimalTestCommand()\n\t_ = app.handleExitCoder(context.Background(), Exit(\"Default Behavior Error\", 42))\n\n\toutput := fakeErrWriter.String()\n\tassert.Contains(t, output, \"Default\", \"Expected Default Behavior from Error Handler\")\n}\n\nfunc TestHandleExitCoder_Custom(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\n\tcmd.ExitErrHandler = func(context.Context, *Command, error) {\n\t\t_, _ = fmt.Fprintln(ErrWriter, \"I'm a Custom error handler, I print what I want!\")\n\t}\n\n\t_ = cmd.handleExitCoder(context.Background(), Exit(\"Default Behavior Error\", 42))\n\n\toutput := fakeErrWriter.String()\n\tassert.Contains(t, output, \"Custom\", \"Expected Custom Behavior from Error Handler\")\n}\n\nfunc TestShellCompletionForIncompleteFlags(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName: \"test-completion\",\n\t\t\t},\n\t\t},\n\t\tEnableShellCompletion: true,\n\t\tShellComplete: func(_ context.Context, cmd *Command) {\n\t\t\tfor _, command := range cmd.Commands {\n\t\t\t\tif command.Hidden {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfor _, name := range command.Names() {\n\t\t\t\t\t_, _ = fmt.Fprintln(cmd.Writer, name)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, fl := range cmd.Flags {\n\t\t\t\tfor _, name := range fl.Names() {\n\t\t\t\t\tif name == GenerateShellCompletionFlag.Names()[0] {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch name = strings.TrimSpace(name); len(name) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\t_, _ = fmt.Fprintln(cmd.Writer, \"-\"+name)\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t_, _ = fmt.Fprintln(cmd.Writer, \"--\"+name)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\treturn fmt.Errorf(\"should not get here\")\n\t\t},\n\t\tWriter: io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--test-completion\", completionFlag})\n\tassert.NoError(t, err, \"app should not return an error\")\n}\n\nfunc TestWhenExitSubCommandWithCodeThenCommandQuitUnexpectedly(t *testing.T) {\n\ttestCode := 104\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.Commands = []*Command{\n\t\t{\n\t\t\tName: \"cmd\",\n\t\t\tCommands: []*Command{\n\t\t\t\t{\n\t\t\t\t\tName: \"subcmd\",\n\t\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\t\treturn Exit(\"exit error\", testCode)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// set user function as ExitErrHandler\n\texitCodeFromExitErrHandler := int(0)\n\tcmd.ExitErrHandler = func(_ context.Context, _ *Command, err error) {\n\t\tif exitErr, ok := err.(ExitCoder); ok {\n\t\t\texitCodeFromExitErrHandler = exitErr.ExitCode()\n\t\t}\n\t}\n\n\t// keep and restore original OsExiter\n\torigExiter := OsExiter\n\tt.Cleanup(func() { OsExiter = origExiter })\n\n\t// set user function as OsExiter\n\texitCodeFromOsExiter := int(0)\n\tOsExiter = func(exitCode int) {\n\t\texitCodeFromOsExiter = exitCode\n\t}\n\n\tr := require.New(t)\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\n\t\t\"myapp\",\n\t\t\"cmd\",\n\t\t\"subcmd\",\n\t}))\n\n\tr.Equal(0, exitCodeFromOsExiter)\n\tr.Equal(testCode, exitCodeFromExitErrHandler)\n}\n\nfunc buildMinimalTestCommand() *Command {\n\t// reset the help flag because tests may have set it\n\tHelpFlag.(*BoolFlag).hasBeenSet = false\n\treturn &Command{Writer: io.Discard}\n}\n\nfunc TestSetupInitializesBothWriters(t *testing.T) {\n\tcmd := &Command{}\n\n\tcmd.setupDefaults([]string{\"test\"})\n\n\tassert.Equal(t, cmd.ErrWriter, os.Stderr, \"expected a.ErrWriter to be os.Stderr\")\n\tassert.Equal(t, cmd.Writer, os.Stdout, \"expected a.Writer to be os.Stdout\")\n}\n\nfunc TestSetupInitializesOnlyNilWriters(t *testing.T) {\n\twr := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tErrWriter: wr,\n\t}\n\n\tcmd.setupDefaults([]string{\"test\"})\n\n\tassert.Equal(t, cmd.ErrWriter, wr, \"expected a.ErrWriter to be a *bytes.Buffer instance\")\n\tassert.Equal(t, cmd.Writer, os.Stdout, \"expected a.Writer to be os.Stdout\")\n}\n\nfunc TestFlagAction(t *testing.T) {\n\tnow := time.Now().UTC().Truncate(time.Minute)\n\ttestCases := []struct {\n\t\tname string\n\t\targs []string\n\t\terr  string\n\t\texp  string\n\t}{\n\t\t{\n\t\t\tname: \"flag_string\",\n\t\t\targs: []string{\"app\", \"--f_string=string\"},\n\t\t\texp:  \"string \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_string_error\",\n\t\t\targs: []string{\"app\", \"--f_string=\"},\n\t\t\terr:  \"flag needs an argument: --f_string=\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_string_error2\",\n\t\t\targs: []string{\"app\", \"--f_string=\", \"--f_bool\"},\n\t\t\terr:  \"flag needs an argument: --f_string=\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_string_slice\",\n\t\t\targs: []string{\"app\", \"--f_string_slice=s1,s2,s3\"},\n\t\t\texp:  \"[s1 s2 s3] \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_string_slice_error\",\n\t\t\targs: []string{\"app\", \"--f_string_slice=err\"},\n\t\t\terr:  \"error string slice\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_bool\",\n\t\t\targs: []string{\"app\", \"--f_bool\"},\n\t\t\texp:  \"true \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_bool_error\",\n\t\t\targs: []string{\"app\", \"--f_bool=false\"},\n\t\t\terr:  \"value is false\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_duration\",\n\t\t\targs: []string{\"app\", \"--f_duration=1h30m20s\"},\n\t\t\texp:  \"1h30m20s \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_duration_error\",\n\t\t\targs: []string{\"app\", \"--f_duration=0\"},\n\t\t\terr:  \"empty duration\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_float64\",\n\t\t\targs: []string{\"app\", \"--f_float64=3.14159\"},\n\t\t\texp:  \"3.14159 \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_float64_error\",\n\t\t\targs: []string{\"app\", \"--f_float64=-1\"},\n\t\t\terr:  \"negative float64\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_float64_slice\",\n\t\t\targs: []string{\"app\", \"--f_float64_slice=1.1,2.2,3.3\"},\n\t\t\texp:  \"[1.1 2.2 3.3] \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_float64_slice_error\",\n\t\t\targs: []string{\"app\", \"--f_float64_slice=-1\"},\n\t\t\terr:  \"invalid float64 slice\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_int\",\n\t\t\targs: []string{\"app\", \"--f_int=1\"},\n\t\t\texp:  \"1 \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_int_error\",\n\t\t\targs: []string{\"app\", \"--f_int=-1\"},\n\t\t\terr:  \"negative int\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_int_slice\",\n\t\t\targs: []string{\"app\", \"--f_int_slice=1,2,3\"},\n\t\t\texp:  \"[1 2 3] \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_int_slice_error\",\n\t\t\targs: []string{\"app\", \"--f_int_slice=-1\"},\n\t\t\terr:  \"invalid int slice\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_timestamp\",\n\t\t\targs: []string{\"app\", \"--f_timestamp\", now.Format(time.DateTime)},\n\t\t\texp:  now.UTC().Format(time.RFC3339) + \" \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_timestamp_error\",\n\t\t\targs: []string{\"app\", \"--f_timestamp\", \"0001-01-01 00:00:00\"},\n\t\t\terr:  \"zero timestamp\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_uint\",\n\t\t\targs: []string{\"app\", \"--f_uint=1\"},\n\t\t\texp:  \"1 \",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_uint_error\",\n\t\t\targs: []string{\"app\", \"--f_uint=0\"},\n\t\t\terr:  \"zero uint64\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_no_action\",\n\t\t\targs: []string{\"app\", \"--f_no_action=xx\"},\n\t\t\texp:  \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"command_flag\",\n\t\t\targs: []string{\"app\", \"c1\", \"--f_string=c1\"},\n\t\t\texp:  \"c1 \",\n\t\t},\n\t\t{\n\t\t\tname: \"subCommand_flag\",\n\t\t\targs: []string{\"app\", \"c1\", \"sub1\", \"--f_string=sub1\"},\n\t\t\texp:  \"sub1 \",\n\t\t},\n\t\t// TBD\n\t\t/*\t\t{\n\t\t\t\tname: \"mixture\",\n\t\t\t\targs: []string{\"app\", \"--f_string=app\", \"--f_uint=1\", \"--f_int_slice=1,2,3\", \"--f_duration=1h30m20s\", \"c1\", \"--f_string=c1\", \"sub1\", \"--f_string=sub1\"},\n\t\t\t\texp:  \"app 1 [1 2 3] 1h30m20s c1 sub1 \",\n\t\t\t},*/\n\t\t{\n\t\t\tname: \"flag_string_map\",\n\t\t\targs: []string{\"app\", \"--f_string_map=s1=s2,s3=\"},\n\t\t\texp:  \"map[s1:s2 s3:]\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag_string_map_error\",\n\t\t\targs: []string{\"app\", \"--f_string_map=err=\"},\n\t\t\terr:  \"error string map\",\n\t\t},\n\t}\n\n\tfor _, test := range testCases {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tout := &bytes.Buffer{}\n\n\t\t\tnewStringFlag := func(local bool) *StringFlag {\n\t\t\t\treturn &StringFlag{\n\t\t\t\t\tLocal: local,\n\t\t\t\t\tName:  \"f_string\",\n\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v string) error {\n\t\t\t\t\t\tif v == \"\" {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"empty string\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\t_, err := cmd.Root().Writer.Write([]byte(v + \" \"))\n\t\t\t\t\t\treturn err\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcmd := &Command{\n\t\t\t\tWriter: out,\n\t\t\t\tName:   \"app\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"c1\",\n\t\t\t\t\t\tFlags:  []Flag{newStringFlag(true)},\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command) error { return nil },\n\t\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:   \"sub1\",\n\t\t\t\t\t\t\t\tAction: func(context.Context, *Command) error { return nil },\n\t\t\t\t\t\t\t\tFlags:  []Flag{newStringFlag(true)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\tnewStringFlag(true),\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName: \"f_no_action\",\n\t\t\t\t\t},\n\t\t\t\t\t&StringSliceFlag{\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tName:  \"f_string_slice\",\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v []string) error {\n\t\t\t\t\t\t\tif v[0] == \"err\" {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"error string slice\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%v \", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&BoolFlag{\n\t\t\t\t\t\tName:  \"f_bool\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v bool) error {\n\t\t\t\t\t\t\tif !v {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"value is false\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%t \", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&DurationFlag{\n\t\t\t\t\t\tName:  \"f_duration\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v time.Duration) error {\n\t\t\t\t\t\t\tif v == 0 {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"empty duration\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, v.String()+\" \")\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&FloatFlag{\n\t\t\t\t\t\tName:  \"f_float64\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v float64) error {\n\t\t\t\t\t\t\tif v < 0 {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"negative float64\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, strconv.FormatFloat(v, 'f', -1, 64)+\" \")\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&FloatSliceFlag{\n\t\t\t\t\t\tName:  \"f_float64_slice\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v []float64) error {\n\t\t\t\t\t\t\tif len(v) > 0 && v[0] < 0 {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"invalid float64 slice\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%v \", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName:  \"f_int\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v int64) error {\n\t\t\t\t\t\t\tif v < 0 {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"negative int\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%v \", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&Int64SliceFlag{\n\t\t\t\t\t\tName:  \"f_int_slice\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v []int64) error {\n\t\t\t\t\t\t\tif len(v) > 0 && v[0] < 0 {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"invalid int slice\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%v \", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&TimestampFlag{\n\t\t\t\t\t\tName:  \"f_timestamp\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tConfig: TimestampConfig{\n\t\t\t\t\t\t\tTimezone: time.UTC,\n\t\t\t\t\t\t\tLayouts:  []string{time.DateTime},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v time.Time) error {\n\t\t\t\t\t\t\tif v.IsZero() {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"zero timestamp\")\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_, err := cmd.Root().Writer.Write([]byte(v.Format(time.RFC3339) + \" \"))\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&Uint64Flag{\n\t\t\t\t\t\tName:  \"f_uint\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v uint64) error {\n\t\t\t\t\t\t\tif v == 0 {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"zero uint64\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%v \", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&StringMapFlag{\n\t\t\t\t\t\tName:  \"f_string_map\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command, v map[string]string) error {\n\t\t\t\t\t\t\tif _, ok := v[\"err\"]; ok {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"error string map\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_, err := fmt.Fprintf(cmd.Root().Writer, \"%v\", v)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(context.Context, *Command) error { return nil },\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), test.args)\n\n\t\t\tr := require.New(t)\n\n\t\t\tif test.err != \"\" {\n\t\t\t\tr.EqualError(err, test.err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tr.NoError(err)\n\t\t\tr.Equal(test.exp, out.String())\n\t\t})\n\t}\n}\n\nfunc TestLocalFlagError(t *testing.T) {\n\tvar topInt int64\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:        \"cmdFlag\",\n\t\t\t\tDestination: &topInt,\n\t\t\t\tLocal:       true,\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"subcmd\",\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\n\t\t\"app\",\n\t\t\"subcmd\",\n\t\t\"--cmdFlag\", \"11\",\n\t})\n\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"flag provided but not defined: -cmdFlag\")\n}\n\nfunc TestPersistentFlag(t *testing.T) {\n\tvar topInt, topPersistentInt, subCommandInt, appOverrideInt int64\n\tvar appFlag string\n\tvar appRequiredFlag string\n\tvar appOverrideCmdInt int64\n\tvar appSliceFloat64 []float64\n\tvar persistentCommandSliceInt []int64\n\tvar persistentFlagActionCount int64\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:        \"persistentCommandFlag\",\n\t\t\t\tDestination: &appFlag,\n\t\t\t\tAction: func(context.Context, *Command, string) error {\n\t\t\t\t\tpersistentFlagActionCount++\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t&Int64SliceFlag{\n\t\t\t\tName:        \"persistentCommandSliceFlag\",\n\t\t\t\tDestination: &persistentCommandSliceInt,\n\t\t\t},\n\t\t\t&FloatSliceFlag{\n\t\t\t\tName:  \"persistentCommandFloatSliceFlag\",\n\t\t\t\tValue: []float64{11.3, 12.5},\n\t\t\t},\n\t\t\t&Int64Flag{\n\t\t\t\tName:        \"persistentCommandOverrideFlag\",\n\t\t\t\tDestination: &appOverrideInt,\n\t\t\t},\n\t\t\t&StringFlag{\n\t\t\t\tName:        \"persistentRequiredCommandFlag\",\n\t\t\t\tRequired:    true,\n\t\t\t\tDestination: &appRequiredFlag,\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"cmd\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName:        \"cmdFlag\",\n\t\t\t\t\t\tDestination: &topInt,\n\t\t\t\t\t\tLocal:       true,\n\t\t\t\t\t},\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName:        \"cmdPersistentFlag\",\n\t\t\t\t\t\tDestination: &topPersistentInt,\n\t\t\t\t\t},\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName:        \"paof\",\n\t\t\t\t\t\tAliases:     []string{\"persistentCommandOverrideFlag\"},\n\t\t\t\t\t\tDestination: &appOverrideCmdInt,\n\t\t\t\t\t\tLocal:       true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"subcmd\",\n\t\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\t\t\tName:        \"cmdFlag\",\n\t\t\t\t\t\t\t\tDestination: &subCommandInt,\n\t\t\t\t\t\t\t\tLocal:       true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\t\t\tappSliceFloat64 = cmd.FloatSlice(\"persistentCommandFloatSliceFlag\")\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\n\t\t\"app\",\n\t\t\"--persistentCommandFlag\", \"hello\",\n\t\t\"--persistentCommandSliceFlag\", \"100\",\n\t\t\"--persistentCommandOverrideFlag\", \"102\",\n\t\t\"cmd\",\n\t\t\"--cmdFlag\", \"12\",\n\t\t\"--persistentCommandSliceFlag\", \"102\",\n\t\t\"--persistentCommandFloatSliceFlag\", \"102.455\",\n\t\t\"--paof\", \"105\",\n\t\t\"--persistentRequiredCommandFlag\", \"hellor\",\n\t\t\"subcmd\",\n\t\t\"--cmdPersistentFlag\", \"20\",\n\t\t\"--cmdFlag\", \"11\",\n\t\t\"--persistentCommandFlag\", \"bar\",\n\t\t\"--persistentCommandSliceFlag\", \"130\",\n\t\t\"--persistentCommandFloatSliceFlag\", \"3.1445\",\n\t})\n\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"bar\", appFlag)\n\tassert.Equal(t, \"hellor\", appRequiredFlag)\n\tassert.Equal(t, int64(12), topInt)\n\tassert.Equal(t, int64(20), topPersistentInt)\n\n\t// this should be changed from app since\n\t// cmd overrides it\n\tassert.Equal(t, int64(102), appOverrideInt)\n\tassert.Equal(t, int64(11), subCommandInt)\n\tassert.Equal(t, int64(105), appOverrideCmdInt)\n\tassert.Equal(t, []int64{100, 102, 130}, persistentCommandSliceInt)\n\tassert.Equal(t, []float64{102.455, 3.1445}, appSliceFloat64)\n\tassert.Equal(t, int64(2), persistentFlagActionCount, \"Expected persistent flag action to be called 2 times\")\n}\n\nfunc TestPersistentFlagIsSet(t *testing.T) {\n\tresult := \"\"\n\tresultIsSet := false\n\n\tapp := &Command{\n\t\tName: \"root\",\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName: \"result\",\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tresult = cmd.String(\"result\")\n\t\t\t\t\tresultIsSet = cmd.IsSet(\"result\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := app.Run(context.Background(), []string{\"root\", \"--result\", \"before\", \"sub\"})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"before\", result)\n\trequire.True(t, resultIsSet)\n\n\terr = app.Run(context.Background(), []string{\"root\", \"sub\", \"--result\", \"after\"})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"after\", result)\n\trequire.True(t, resultIsSet)\n}\n\nfunc TestRequiredFlagDelayed(t *testing.T) {\n\tsf := &StringFlag{\n\t\tName:     \"result\",\n\t\tRequired: true,\n\t}\n\n\texpectedErr := &errRequiredFlags{\n\t\tmissingFlags: []string{sf.Name},\n\t}\n\n\ttests := []struct {\n\t\tname        string\n\t\targs        []string\n\t\terrExpected error\n\t}{\n\t\t{\n\t\t\tname:        \"leaf help\",\n\t\t\targs:        []string{\"root\", \"sub\", \"-h\"},\n\t\t\terrExpected: nil,\n\t\t},\n\t\t{\n\t\t\tname:        \"leaf action\",\n\t\t\targs:        []string{\"root\", \"sub\"},\n\t\t\terrExpected: expectedErr,\n\t\t},\n\t\t{\n\t\t\tname:        \"leaf flags set\",\n\t\t\targs:        []string{\"root\", \"sub\", \"--if\", \"10\"},\n\t\t\terrExpected: expectedErr,\n\t\t},\n\t\t{\n\t\t\tname:        \"leaf invalid flags set\",\n\t\t\targs:        []string{\"root\", \"sub\", \"--xx\"},\n\t\t\terrExpected: expectedErr,\n\t\t},\n\t}\n\n\tapp := &Command{\n\t\tName: \"root\",\n\t\tFlags: []Flag{\n\t\t\tsf,\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName:     \"if\",\n\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\terr := app.Run(context.Background(), test.args)\n\t\t\tif test.errExpected == nil {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.ErrorAs(t, err, &test.errExpected)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRequiredPersistentFlag(t *testing.T) {\n\tapp := &Command{\n\t\tName: \"root\",\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:     \"result\",\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"sub\",\n\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := app.Run(context.Background(), []string{\"root\", \"sub\"})\n\trequire.Error(t, err)\n\n\terr = app.Run(context.Background(), []string{\"root\", \"sub\", \"--result\", \"after\"})\n\trequire.NoError(t, err)\n}\n\nfunc TestFlagDuplicates(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\targs        []string\n\t\terrExpected bool\n\t}{\n\t\t{\n\t\t\tname: \"all args present once\",\n\t\t\targs: []string{\"foo\", \"--sflag\", \"hello\", \"--isflag\", \"1\", \"--isflag\", \"2\", \"--fsflag\", \"2.0\", \"--iflag\", \"10\", \"--bifflag\"},\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate non slice flag(duplicatable)\",\n\t\t\targs: []string{\"foo\", \"--sflag\", \"hello\", \"--isflag\", \"1\", \"--isflag\", \"2\", \"--fsflag\", \"2.0\", \"--iflag\", \"10\", \"--iflag\", \"20\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"duplicate non slice flag(non duplicatable)\",\n\t\t\targs:        []string{\"foo\", \"--sflag\", \"hello\", \"--isflag\", \"1\", \"--isflag\", \"2\", \"--fsflag\", \"2.0\", \"--iflag\", \"10\", \"--sflag\", \"trip\"},\n\t\t\terrExpected: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"duplicate slice flag(non duplicatable)\",\n\t\t\targs:        []string{\"foo\", \"--sflag\", \"hello\", \"--isflag\", \"1\", \"--isflag\", \"2\", \"--fsflag\", \"2.0\", \"--fsflag\", \"3.0\", \"--iflag\", \"10\"},\n\t\t\terrExpected: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"duplicate bool inverse flag(non duplicatable)\",\n\t\t\targs:        []string{\"foo\", \"--bifflag\", \"--bifflag\"},\n\t\t\terrExpected: true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName:     \"sflag\",\n\t\t\t\t\t\tOnlyOnce: true,\n\t\t\t\t\t},\n\t\t\t\t\t&Int64SliceFlag{\n\t\t\t\t\t\tName: \"isflag\",\n\t\t\t\t\t},\n\t\t\t\t\t&FloatSliceFlag{\n\t\t\t\t\t\tName:     \"fsflag\",\n\t\t\t\t\t\tOnlyOnce: true,\n\t\t\t\t\t},\n\t\t\t\t\t&BoolWithInverseFlag{\n\t\t\t\t\t\tName:     \"bifflag\",\n\t\t\t\t\t\tOnlyOnce: true,\n\t\t\t\t\t},\n\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\tName: \"iflag\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), test.args)\n\t\t\tif test.errExpected {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestShorthandCommand(t *testing.T) {\n\taf := func(p *int) ActionFunc {\n\t\treturn func(context.Context, *Command) error {\n\t\t\t*p = *p + 1\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tvar cmd1, cmd2 int\n\n\tcmd := &Command{\n\t\tPrefixMatchCommands: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:    \"cthdisd\",\n\t\t\t\tAliases: []string{\"cth\"},\n\t\t\t\tAction:  af(&cmd1),\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"cthertoop\",\n\t\t\t\tAliases: []string{\"cer\"},\n\t\t\t\tAction:  af(&cmd2),\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"cth\"})\n\tassert.NoError(t, err)\n\tassert.True(t, cmd1 == 1 && cmd2 == 0, \"Expected command1 to be triggered once\")\n\n\tcmd1 = 0\n\tcmd2 = 0\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"cthd\"})\n\tassert.NoError(t, err)\n\tassert.True(t, cmd1 == 1 && cmd2 == 0, \"Expected command1 to be triggered once\")\n\n\tcmd1 = 0\n\tcmd2 = 0\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"cthe\"})\n\tassert.NoError(t, err)\n\tassert.True(t, cmd1 == 1 && cmd2 == 0, \"Expected command1 to be triggered once\")\n\n\tcmd1 = 0\n\tcmd2 = 0\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"cthert\"})\n\tassert.NoError(t, err)\n\tassert.True(t, cmd1 == 0 && cmd2 == 1, \"Expected command1 to be triggered once\")\n\n\tcmd1 = 0\n\tcmd2 = 0\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"cthet\"})\n\tassert.NoError(t, err)\n\tassert.True(t, cmd1 == 0 && cmd2 == 1, \"Expected command1 to be triggered once\")\n}\n\nfunc TestCommand_Int(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:  \"myflag\",\n\t\t\t\tValue: 12,\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: 13,\n\t\t\t},\n\t\t},\n\t\tparent: pCmd,\n\t}\n\n\trequire.Equal(t, int64(12), cmd.Int64(\"myflag\"))\n\trequire.Equal(t, int64(13), cmd.Int64(\"top-flag\"))\n}\n\nfunc TestCommand_Uint(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Uint64Flag{\n\t\t\t\tName:  \"myflagUint\",\n\t\t\t\tValue: 13,\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Uint64Flag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: 14,\n\t\t\t},\n\t\t},\n\t\tparent: pCmd,\n\t}\n\n\trequire.Equal(t, uint64(13), cmd.Uint64(\"myflagUint\"))\n\trequire.Equal(t, uint64(14), cmd.Uint64(\"top-flag\"))\n}\n\nfunc TestCommand_Float64(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{\n\t\t\t\tName:  \"myflag\",\n\t\t\t\tValue: 17,\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: 18,\n\t\t\t},\n\t\t},\n\t\tparent: pCmd,\n\t}\n\n\tr := require.New(t)\n\tr.Equal(float64(17), cmd.Float(\"myflag\"))\n\tr.Equal(float64(18), cmd.Float(\"top-flag\"))\n}\n\nfunc TestCommand_Duration(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&DurationFlag{\n\t\t\t\tName:  \"myflag\",\n\t\t\t\tValue: 12 * time.Second,\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&DurationFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: 13 * time.Second,\n\t\t\t},\n\t\t},\n\t\tparent: pCmd,\n\t}\n\n\tr := require.New(t)\n\tr.Equal(12*time.Second, cmd.Duration(\"myflag\"))\n\tr.Equal(13*time.Second, cmd.Duration(\"top-flag\"))\n}\n\nfunc TestCommand_Timestamp(t *testing.T) {\n\tt1 := time.Time{}.Add(12 * time.Second)\n\tt2 := time.Time{}.Add(13 * time.Second)\n\n\tcmd := &Command{\n\t\tName: \"hello\",\n\t\tFlags: []Flag{\n\t\t\t&TimestampFlag{\n\t\t\t\tName:  \"myflag\",\n\t\t\t\tValue: t1,\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&TimestampFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: t2,\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\tcmd,\n\t\t},\n\t}\n\n\terr := pCmd.Run(context.Background(), []string{\"foo\", \"hello\"})\n\tassert.NoError(t, err)\n\n\tr := require.New(t)\n\tr.Equal(t1, cmd.Timestamp(\"myflag\"))\n\tr.Equal(t2, cmd.Timestamp(\"top-flag\"))\n}\n\nfunc TestCommand_String(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:  \"myflag\",\n\t\t\t\tValue: \"hello world\",\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: \"hai veld\",\n\t\t\t},\n\t\t},\n\t\tparent: pCmd,\n\t}\n\n\tr := require.New(t)\n\tr.Equal(\"hello world\", cmd.String(\"myflag\"))\n\tr.Equal(\"hai veld\", cmd.String(\"top-flag\"))\n\n\tr.Equal(\"hai veld\", cmd.String(\"top-flag\"))\n}\n\nfunc TestCommand_Bool(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"myflag\",\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: true,\n\t\t\t},\n\t\t},\n\t\tparent: pCmd,\n\t}\n\n\tr := require.New(t)\n\tr.False(cmd.Bool(\"myflag\"))\n\tr.True(cmd.Bool(\"top-flag\"))\n}\n\nfunc TestCommand_Value(t *testing.T) {\n\tsubCmd := &Command{\n\t\tName: \"test\",\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:    \"myflag\",\n\t\t\t\tUsage:   \"doc\",\n\t\t\t\tAliases: []string{\"m\", \"mf\"},\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:    \"top-flag\",\n\t\t\t\tUsage:   \"doc\",\n\t\t\t\tAliases: []string{\"t\", \"tf\"},\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\tsubCmd,\n\t\t},\n\t}\n\tt.Run(\"flag name\", func(t *testing.T) {\n\t\tr := require.New(t)\n\t\terr := cmd.Run(buildTestContext(t), []string{\"main\", \"--top-flag\", \"13\", \"test\", \"--myflag\", \"14\"})\n\n\t\tr.NoError(err)\n\t\tr.Equal(int64(13), cmd.Value(\"top-flag\"))\n\t\tr.Equal(int64(13), cmd.Value(\"t\"))\n\t\tr.Equal(int64(13), cmd.Value(\"tf\"))\n\n\t\tr.Equal(int64(14), subCmd.Value(\"myflag\"))\n\t\tr.Equal(int64(14), subCmd.Value(\"m\"))\n\t\tr.Equal(int64(14), subCmd.Value(\"mf\"))\n\t})\n\n\tt.Run(\"flag aliases\", func(t *testing.T) {\n\t\tr := require.New(t)\n\t\terr := cmd.Run(buildTestContext(t), []string{\"main\", \"-tf\", \"15\", \"test\", \"-m\", \"16\"})\n\n\t\tr.NoError(err)\n\t\tr.Equal(int64(15), cmd.Value(\"top-flag\"))\n\t\tr.Equal(int64(15), cmd.Value(\"t\"))\n\t\tr.Equal(int64(15), cmd.Value(\"tf\"))\n\n\t\tr.Equal(int64(16), subCmd.Value(\"myflag\"))\n\t\tr.Equal(int64(16), subCmd.Value(\"m\"))\n\t\tr.Equal(int64(16), subCmd.Value(\"mf\"))\n\t\tr.Nil(cmd.Value(\"unknown-flag\"))\n\t})\n}\n\nfunc TestCommand_Value_InvalidFlagAccessHandler(t *testing.T) {\n\tvar flagName string\n\tcmd := &Command{\n\t\tInvalidFlagAccessHandler: func(_ context.Context, _ *Command, name string) {\n\t\t\tflagName = name\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"command\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"subcommand\",\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\t\t\tcmd.Value(\"missing\")\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"run\", \"command\", \"subcommand\"}))\n\tr.Equal(\"missing\", flagName)\n}\n\nfunc TestCommand_Args(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"myflag\",\n\t\t\t},\n\t\t},\n\t}\n\t_ = cmd.Run(context.Background(), []string{\"\", \"--myflag\", \"bat\", \"baz\"})\n\n\tr := require.New(t)\n\tr.Equal(2, cmd.Args().Len())\n\tr.True(cmd.Bool(\"myflag\"))\n\tr.Equal(2, cmd.NArg())\n}\n\nfunc TestCommand_IsSet(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"frob\",\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"one-flag\",\n\t\t\t},\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"two-flag\",\n\t\t\t},\n\t\t\t&StringFlag{\n\t\t\t\tName:  \"three-flag\",\n\t\t\t\tValue: \"hello world\",\n\t\t\t},\n\t\t},\n\t}\n\tpCmd := &Command{\n\t\tName: \"root\",\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: true,\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\tcmd,\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(pCmd.Run(context.Background(), []string{\"foo\", \"frob\", \"--one-flag\", \"--top-flag\", \"--two-flag\", \"--three-flag\", \"dds\"}))\n\n\tr.True(cmd.IsSet(\"one-flag\"))\n\tr.True(cmd.IsSet(\"two-flag\"))\n\tr.True(cmd.IsSet(\"three-flag\"))\n\tr.True(cmd.IsSet(\"top-flag\"))\n\tr.False(cmd.IsSet(\"bogus\"))\n}\n\n// XXX Corresponds to hack in context.IsSet for flags with EnvVar field\n// Should be moved to `flag_test` in v2\nfunc TestCommand_IsSet_fromEnv(t *testing.T) {\n\tvar (\n\t\ttimeoutIsSet, tIsSet    bool\n\t\tnoEnvVarIsSet, nIsSet   bool\n\t\tpasswordIsSet, pIsSet   bool\n\t\tunparsableIsSet, uIsSet bool\n\t)\n\n\tt.Setenv(\"APP_TIMEOUT_SECONDS\", \"15.5\")\n\tt.Setenv(\"APP_PASSWORD\", \"\")\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{Name: \"timeout\", Aliases: []string{\"t\"}, Local: true, Sources: EnvVars(\"APP_TIMEOUT_SECONDS\")},\n\t\t\t&StringFlag{Name: \"password\", Aliases: []string{\"p\"}, Local: true, Sources: EnvVars(\"APP_PASSWORD\")},\n\t\t\t&FloatFlag{Name: \"unparsable\", Aliases: []string{\"u\"}, Local: true, Sources: EnvVars(\"APP_UNPARSABLE\")},\n\t\t\t&FloatFlag{Name: \"no-env-var\", Aliases: []string{\"n\"}, Local: true},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\ttimeoutIsSet = cmd.IsSet(\"timeout\")\n\t\t\ttIsSet = cmd.IsSet(\"t\")\n\t\t\tpasswordIsSet = cmd.IsSet(\"password\")\n\t\t\tpIsSet = cmd.IsSet(\"p\")\n\t\t\tunparsableIsSet = cmd.IsSet(\"unparsable\")\n\t\t\tuIsSet = cmd.IsSet(\"u\")\n\t\t\tnoEnvVarIsSet = cmd.IsSet(\"no-env-var\")\n\t\t\tnIsSet = cmd.IsSet(\"n\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"run\"}))\n\tr.True(timeoutIsSet)\n\tr.True(tIsSet)\n\tr.True(passwordIsSet)\n\tr.True(pIsSet)\n\tr.False(noEnvVarIsSet)\n\tr.False(nIsSet)\n\n\tt.Setenv(\"APP_UNPARSABLE\", \"foobar\")\n\n\tr.Error(cmd.Run(buildTestContext(t), []string{\"run\"}))\n\tr.False(unparsableIsSet)\n\tr.False(uIsSet)\n}\n\nfunc TestCommand_NumFlags(t *testing.T) {\n\trootCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName:  \"myflagGlobal\",\n\t\t\t\tValue: true,\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"myflag\",\n\t\t\t},\n\t\t\t&StringFlag{\n\t\t\t\tName:  \"otherflag\",\n\t\t\t\tValue: \"hello world\",\n\t\t\t},\n\t\t},\n\t}\n\n\t_ = cmd.Run(context.Background(), []string{\"\", \"--myflag\", \"--otherflag=foo\"})\n\t_ = rootCmd.Run(context.Background(), []string{\"\", \"--myflagGlobal\"})\n\trequire.Equal(t, 2, cmd.NumFlags())\n\tactualFlags := cmd.LocalFlagNames()\n\tsort.Strings(actualFlags)\n\n\trequire.Equal(t, []string{\"myflag\", \"otherflag\"}, actualFlags)\n\n\tactualFlags = cmd.FlagNames()\n\tsort.Strings(actualFlags)\n\n\trequire.Equal(t, []string{\"myflag\", \"otherflag\"}, actualFlags)\n\n\tcmd.parent = rootCmd\n\tlineage := cmd.Lineage()\n\n\tr := require.New(t)\n\tr.Equal(2, len(lineage))\n\tr.Equal(cmd, lineage[0])\n\tr.Equal(rootCmd, lineage[1])\n}\n\nfunc TestCommand_Set(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:  \"int\",\n\t\t\t\tValue: 5,\n\t\t\t},\n\t\t},\n\t}\n\tr := require.New(t)\n\n\tr.False(cmd.IsSet(\"int\"))\n\tr.NoError(cmd.Set(\"int\", \"1\"))\n\tr.Equal(int64(1), cmd.Int64(\"int\"))\n\tr.True(cmd.IsSet(\"int\"))\n}\n\nfunc TestCommand_Set_InvalidFlagAccessHandler(t *testing.T) {\n\tvar flagName string\n\tcmd := &Command{\n\t\tInvalidFlagAccessHandler: func(_ context.Context, _ *Command, name string) {\n\t\t\tflagName = name\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.True(cmd.Set(\"missing\", \"\") != nil)\n\tr.Equal(\"missing\", flagName)\n}\n\nfunc TestCommand_lookupFlag(t *testing.T) {\n\tpCmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName:  \"top-flag\",\n\t\t\t\tValue: true,\n\t\t\t},\n\t\t},\n\t}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName: \"local-flag\",\n\t\t\t},\n\t\t},\n\t}\n\t_ = cmd.Run(context.Background(), []string{\"--local-flag\"})\n\tpCmd.Commands = []*Command{cmd}\n\t_ = pCmd.Run(context.Background(), []string{\"--top-flag\"})\n\n\tr := require.New(t)\n\n\tfs := cmd.lookupFlag(\"top-flag\")\n\tr.Equal(pCmd.Flags[0], fs)\n\n\tfs = cmd.lookupFlag(\"local-flag\")\n\tr.Equal(cmd.Flags[0], fs)\n\tr.Nil(cmd.lookupFlag(\"frob\"))\n}\n\nfunc TestCommandAttributeAccessing(t *testing.T) {\n\ttdata := []struct {\n\t\ttestCase     string\n\t\tsetBoolInput string\n\t\tctxBoolInput string\n\t\tparent       *Command\n\t}{\n\t\t{\n\t\t\ttestCase:     \"empty\",\n\t\t\tsetBoolInput: \"\",\n\t\t\tctxBoolInput: \"\",\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"empty_with_background_context\",\n\t\t\tsetBoolInput: \"\",\n\t\t\tctxBoolInput: \"\",\n\t\t\tparent:       &Command{},\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"empty_set_bool_and_present_ctx_bool\",\n\t\t\tsetBoolInput: \"\",\n\t\t\tctxBoolInput: \"ctx-bool\",\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"present_set_bool_and_present_ctx_bool_with_background_context\",\n\t\t\tsetBoolInput: \"\",\n\t\t\tctxBoolInput: \"ctx-bool\",\n\t\t\tparent:       &Command{},\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"present_set_bool_and_present_ctx_bool\",\n\t\t\tsetBoolInput: \"ctx-bool\",\n\t\t\tctxBoolInput: \"ctx-bool\",\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"present_set_bool_and_present_ctx_bool_with_background_context\",\n\t\t\tsetBoolInput: \"ctx-bool\",\n\t\t\tctxBoolInput: \"ctx-bool\",\n\t\t\tparent:       &Command{},\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"present_set_bool_and_different_ctx_bool\",\n\t\t\tsetBoolInput: \"ctx-bool\",\n\t\t\tctxBoolInput: \"not-ctx-bool\",\n\t\t},\n\t\t{\n\t\t\ttestCase:     \"present_set_bool_and_different_ctx_bool_with_background_context\",\n\t\t\tsetBoolInput: \"ctx-bool\",\n\t\t\tctxBoolInput: \"not-ctx-bool\",\n\t\t\tparent:       &Command{},\n\t\t},\n\t}\n\n\tfor _, test := range tdata {\n\t\tt.Run(test.testCase, func(t *testing.T) {\n\t\t\tcmd := &Command{parent: test.parent}\n\n\t\t\trequire.False(t, cmd.Bool(test.ctxBoolInput))\n\t\t})\n\t}\n}\n\nfunc TestCheckRequiredFlags(t *testing.T) {\n\ttdata := []struct {\n\t\ttestCase              string\n\t\tparseInput            []string\n\t\tenvVarInput           [2]string\n\t\tflags                 []Flag\n\t\texpectedAnError       bool\n\t\texpectedErrorContents []string\n\t}{\n\t\t{\n\t\t\ttestCase: \"empty\",\n\t\t},\n\t\t{\n\t\t\ttestCase: \"optional\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"optionalFlag\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t},\n\t\t\texpectedAnError:       true,\n\t\t\texpectedErrorContents: []string{\"requiredFlag\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_and_present\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t},\n\t\t\tparseInput: []string{\"--requiredFlag\", \"myinput\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_and_present_via_env_var\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true, Sources: EnvVars(\"REQUIRED_FLAG\")},\n\t\t\t},\n\t\t\tenvVarInput: [2]string{\"REQUIRED_FLAG\", \"true\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_and_optional\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t\t&StringFlag{Name: \"optionalFlag\"},\n\t\t\t},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_and_optional_and_optional_present\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t\t&StringFlag{Name: \"optionalFlag\"},\n\t\t\t},\n\t\t\tparseInput:      []string{\"--optionalFlag\", \"myinput\"},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_and_optional_and_optional_present_via_env_var\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t\t&StringFlag{Name: \"optionalFlag\", Sources: EnvVars(\"OPTIONAL_FLAG\")},\n\t\t\t},\n\t\t\tenvVarInput:     [2]string{\"OPTIONAL_FLAG\", \"true\"},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_and_optional_and_required_present\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t\t&StringFlag{Name: \"optionalFlag\"},\n\t\t\t},\n\t\t\tparseInput: []string{\"--requiredFlag\", \"myinput\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"two_required\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlagOne\", Required: true},\n\t\t\t\t&StringFlag{Name: \"requiredFlagTwo\", Required: true},\n\t\t\t},\n\t\t\texpectedAnError:       true,\n\t\t\texpectedErrorContents: []string{\"requiredFlagOne\", \"requiredFlagTwo\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"two_required_and_one_present\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t\t&StringFlag{Name: \"requiredFlagTwo\", Required: true},\n\t\t\t},\n\t\t\tparseInput:      []string{\"--requiredFlag\", \"myinput\"},\n\t\t\texpectedAnError: true,\n\t\t},\n\t\t{\n\t\t\ttestCase: \"two_required_and_both_present\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t\t\t&StringFlag{Name: \"requiredFlagTwo\", Required: true},\n\t\t\t},\n\t\t\tparseInput: []string{\"--requiredFlag\", \"myinput\", \"--requiredFlagTwo\", \"myinput\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_flag_with_short_name\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringSliceFlag{Name: \"names\", Aliases: []string{\"N\"}, Required: true},\n\t\t\t},\n\t\t\tparseInput: []string{\"-N\", \"asd\", \"-N\", \"qwe\"},\n\t\t},\n\t\t{\n\t\t\ttestCase: \"required_flag_with_multiple_short_names\",\n\t\t\tflags: []Flag{\n\t\t\t\t&StringSliceFlag{Name: \"names\", Aliases: []string{\"N\", \"n\"}, Required: true},\n\t\t\t},\n\t\t\tparseInput: []string{\"-n\", \"asd\", \"-n\", \"qwe\"},\n\t\t},\n\t\t{\n\t\t\ttestCase:              \"required_flag_with_short_alias_not_printed_on_error\",\n\t\t\texpectedAnError:       true,\n\t\t\texpectedErrorContents: []string{\"Required flag \\\"names\\\" not set\"},\n\t\t\tflags: []Flag{\n\t\t\t\t&StringSliceFlag{Name: \"names\", Aliases: []string{\"n\"}, Required: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttestCase:              \"required_flag_with_one_character\",\n\t\t\texpectedAnError:       true,\n\t\t\texpectedErrorContents: []string{\"Required flag \\\"n\\\" not set\"},\n\t\t\tflags: []Flag{\n\t\t\t\t&StringFlag{Name: \"n\", Required: true},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tdata {\n\t\tt.Run(test.testCase, func(t *testing.T) {\n\t\t\t// setup\n\t\t\tif test.envVarInput[0] != \"\" {\n\t\t\t\tt.Setenv(test.envVarInput[0], test.envVarInput[1])\n\t\t\t}\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:  \"foo\",\n\t\t\t\tFlags: test.flags,\n\t\t\t}\n\t\t\targs := []string{\"foo\"}\n\t\t\targs = append(args, test.parseInput...)\n\t\t\t_ = cmd.Run(context.Background(), args)\n\n\t\t\terr := cmd.checkAllRequiredFlags()\n\n\t\t\t// assertions\n\t\t\tif test.expectedAnError {\n\t\t\t\tassert.NotNil(t, err)\n\t\t\t} else {\n\t\t\t\tassert.Nil(t, err)\n\t\t\t}\n\t\t\tfor _, errString := range test.expectedErrorContents {\n\t\t\t\tif err != nil {\n\t\t\t\t\tassert.ErrorContains(t, err, errString)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCheckRequiredFlagsWithOnUsageError(t *testing.T) {\n\texpectedError := errors.New(\"OnUsageError\")\n\tcmd := &Command{\n\t\tName: \"foo\",\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"requiredFlag\", Required: true},\n\t\t},\n\t\tOnUsageError: func(_ context.Context, _ *Command, _ error, _ bool) error {\n\t\t\treturn expectedError\n\t\t},\n\t}\n\tactualError := cmd.Run(buildTestContext(t), []string{\"requiredFlag\"})\n\trequire.ErrorIs(t, actualError, expectedError)\n}\n\nfunc TestCommand_ParentCommand_Set(t *testing.T) {\n\tcmd := &Command{\n\t\tparent: &Command{\n\t\t\tFlags: []Flag{\n\t\t\t\t&StringFlag{\n\t\t\t\t\tName: \"Name\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Set(\"Name\", \"aaa\")\n\tassert.NoError(t, err)\n}\n\nfunc TestCommandStringDashOption(t *testing.T) {\n\ttests := []struct {\n\t\tname                string\n\t\tshortOptionHandling bool\n\t\targs                []string\n\t}{\n\t\t{\n\t\t\tname: \"double dash separate value\",\n\t\t\targs: []string{\"foo\", \"--bar\", \"-\", \"test\"},\n\t\t},\n\t\t{\n\t\t\tname: \"single dash separate value\",\n\t\t\targs: []string{\"foo\", \"-bar\", \"-\", \"test\"},\n\t\t},\n\t\t/*{\n\t\t\tname:                \"single dash combined value\",\n\t\t\targs:                []string{\"foo\", \"-b-\", \"test\"},\n\t\t\tshortOptionHandling: true,\n\t\t},*/\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:                   \"foo\",\n\t\t\t\tUseShortOptionHandling: test.shortOptionHandling,\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName:    \"bar\",\n\t\t\t\t\t\tAliases: []string{\"b\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), test.args)\n\t\t\tassert.NoError(t, err)\n\n\t\t\tassert.Equal(t, \"-\", cmd.String(\"b\"))\n\t\t})\n\t}\n}\n\nfunc TestCommandReadArgsFromStdIn(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tinput         string\n\t\targs          []string\n\t\texpectedInt   int64\n\t\texpectedFloat float64\n\t\texpectedSlice []string\n\t\texpectError   bool\n\t}{\n\t\t{\n\t\t\tname:          \"empty\",\n\t\t\tinput:         \"\",\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   0,\n\t\t\texpectedFloat: 0.0,\n\t\t\texpectedSlice: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"empty2\",\n\t\t\tinput: `\n\n\t\t\t`,\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   0,\n\t\t\texpectedFloat: 0.0,\n\t\t\texpectedSlice: []string{},\n\t\t},\n\t\t{\n\t\t\tname:          \"intflag-from-input\",\n\t\t\tinput:         \"--if=100\",\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   100,\n\t\t\texpectedFloat: 0.0,\n\t\t\texpectedSlice: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"intflag-from-input2\",\n\t\t\tinput: `\n\t\t\t--if\n\n\t\t\t100`,\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   100,\n\t\t\texpectedFloat: 0.0,\n\t\t\texpectedSlice: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"multiflag-from-input\",\n\t\t\tinput: `\n\t\t\t--if\n\n\t\t\t100\n\t\t\t--ff      100.1\n\n\t\t\t--ssf hello\n\t\t\t--ssf\n\n\t\t\t\"hello\n  123\n44\"\n\t\t\t`,\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   100,\n\t\t\texpectedFloat: 100.1,\n\t\t\texpectedSlice: []string{\"hello\", \"hello\\n  123\\n44\"},\n\t\t},\n\t\t{\n\t\t\tname: \"end-args\",\n\t\t\tinput: `\n\t\t\t--if\n\n\t\t\t100\n\t\t\t--\n\t\t\t--ff      100.1\n\n\t\t\t--ssf hello\n\t\t\t--ssf\n\n\t\t\thell02\n\t\t\t`,\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   100,\n\t\t\texpectedFloat: 0,\n\t\t\texpectedSlice: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid string\",\n\t\t\tinput: `\n\t\t\t\"\n\t\t\t`,\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedInt:   0,\n\t\t\texpectedFloat: 0,\n\t\t\texpectedSlice: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid string2\",\n\t\t\tinput: `\n\t\t\t--if\n\t\t\t\"\n\t\t\t`,\n\t\t\targs:        []string{\"foo\"},\n\t\t\texpectError: true,\n\t\t},\n\t\t{\n\t\t\tname: \"incomplete string\",\n\t\t\tinput: `\n\t\t\t--ssf\n\t\t\t\"\n\t\t\thello\n\t\t\t`,\n\t\t\targs:          []string{\"foo\"},\n\t\t\texpectedSlice: []string{\"hello\"},\n\t\t},\n\t}\n\n\tfor _, tst := range tests {\n\t\tt.Run(tst.name, func(t *testing.T) {\n\t\t\tr := require.New(t)\n\n\t\t\tfp, err := os.CreateTemp(\"\", \"readargs\")\n\t\t\tr.NoError(err)\n\t\t\t_, err = fp.Write([]byte(tst.input))\n\t\t\tr.NoError(err)\n\t\t\tfp.Close()\n\n\t\t\tcmd := buildMinimalTestCommand()\n\t\t\tcmd.ReadArgsFromStdin = true\n\t\t\tcmd.Reader, err = os.Open(fp.Name())\n\t\t\tr.NoError(err)\n\t\t\tcmd.Flags = []Flag{\n\t\t\t\t&Int64Flag{\n\t\t\t\t\tName: \"if\",\n\t\t\t\t},\n\t\t\t\t&FloatFlag{\n\t\t\t\t\tName: \"ff\",\n\t\t\t\t},\n\t\t\t\t&StringSliceFlag{\n\t\t\t\t\tName: \"ssf\",\n\t\t\t\t\tConfig: StringConfig{\n\t\t\t\t\t\tTrimSpace: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tactionCalled := false\n\t\t\tcmd.Action = func(ctx context.Context, c *Command) error {\n\t\t\t\tr.Equal(tst.expectedInt, c.Int64(\"if\"))\n\t\t\t\tr.Equal(tst.expectedFloat, c.Float(\"ff\"))\n\t\t\t\tr.Equal(tst.expectedSlice, c.StringSlice(\"ssf\"))\n\t\t\t\tactionCalled = true\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\terr = cmd.Run(context.Background(), tst.args)\n\t\t\tif !tst.expectError {\n\t\t\t\tr.NoError(err)\n\t\t\t\tr.True(actionCalled)\n\t\t\t} else {\n\t\t\t\tr.Error(err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestZeroValueCommand(t *testing.T) {\n\tvar cmd Command\n\tassert.NoError(t, cmd.Run(context.Background(), []string{\"foo\"}))\n}\n\nfunc TestCommandInvalidName(t *testing.T) {\n\tvar cmd Command\n\tassert.Equal(t, int64(0), cmd.Int64(\"foo\"))\n\tassert.Equal(t, uint64(0), cmd.Uint64(\"foo\"))\n\tassert.Equal(t, float64(0), cmd.Float(\"foo\"))\n\tassert.Equal(t, \"\", cmd.String(\"foo\"))\n\tassert.Equal(t, time.Time{}, cmd.Timestamp(\"foo\"))\n\tassert.Equal(t, time.Duration(0), cmd.Duration(\"foo\"))\n\n\tassert.Equal(t, []int64(nil), cmd.Int64Slice(\"foo\"))\n\tassert.Equal(t, []uint64(nil), cmd.Uint64Slice(\"foo\"))\n\tassert.Equal(t, []float64(nil), cmd.FloatSlice(\"foo\"))\n\tassert.Equal(t, []string(nil), cmd.StringSlice(\"foo\"))\n}\n\nfunc TestCommandCategories(t *testing.T) {\n\tvar cc commandCategories = []*commandCategory{\n\t\t{\n\t\t\tname:     \"foo\",\n\t\t\tcommands: []*Command{},\n\t\t},\n\t\t{\n\t\t\tname:     \"bar\",\n\t\t\tcommands: []*Command{},\n\t\t},\n\t\t{\n\t\t\tname:     \"goo\",\n\t\t\tcommands: nil,\n\t\t},\n\t}\n\n\tsort.Sort(&cc)\n\n\tvar prev *commandCategory\n\tfor _, c := range cc {\n\t\tif prev != nil {\n\t\t\tassert.LessOrEqual(t, prev.name, c.name)\n\t\t}\n\t\tprev = c\n\t\tassert.Equal(t, []*Command(nil), c.VisibleCommands())\n\t}\n}\n\nfunc TestCommandSliceFlagSeparator(t *testing.T) {\n\tcmd := &Command{\n\t\tSliceFlagSeparator: \";\",\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{\n\t\t\t\tName: \"foo\",\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"app\", \"--foo\", \"ff;dd;gg\", \"--foo\", \"t,u\"}))\n\tr.Equal([]string{\"ff\", \"dd\", \"gg\", \"t,u\"}, cmd.Value(\"foo\"))\n}\n\nfunc TestCommandMapKeyValueFlagSeparator(t *testing.T) {\n\tcmd := &Command{\n\t\tMapFlagKeyValueSeparator: \":\",\n\t\tFlags: []Flag{\n\t\t\t&StringMapFlag{\n\t\t\t\tName: \"f_string_map\",\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"app\", \"--f_string_map\", \"s1:s2,s3:\", \"--f_string_map\", \"s4:s5\"}))\n\texp := map[string]string{\n\t\t\"s1\": \"s2\",\n\t\t\"s3\": \"\",\n\t\t\"s4\": \"s5\",\n\t}\n\tr.Equal(exp, cmd.Value(\"f_string_map\"))\n}\n\n// TestStringFlagTerminator tests the string flag \"--flag\" with \"--\" terminator.\nfunc TestStringFlagTerminator(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tinput        []string\n\t\texpectFlag   string\n\t\texpectArgs   []string\n\t\texpectErr    bool\n\t\terrorContain string\n\t}{\n\t\t{\n\t\t\tname:       \"flag and args after terminator\",\n\t\t\tinput:      []string{\"test\", \"--flag\", \"x\", \"--\", \"test\", \"a1\", \"a2\", \"a3\"},\n\t\t\texpectFlag: \"x\",\n\t\t\texpectArgs: []string{\"test\", \"a1\", \"a2\", \"a3\"},\n\t\t},\n\t\t/*\t{\n\t\t\tname:         \"missing flag value due to terminator\",\n\t\t\tinput:        []string{\"test\", \"--flag\", \"--\", \"x\"},\n\t\t\texpectErr:    true,\n\t\t\terrorContain: \"flag needs an argument\",\n\t\t},*/\n\t\t{\n\t\t\tname:       \"terminator with no trailing args\",\n\t\t\tinput:      []string{\"test\", \"--flag\", \"x\", \"--\"},\n\t\t\texpectFlag: \"x\",\n\t\t\texpectArgs: []string{},\n\t\t},\n\t\t{\n\t\t\tname:       \"no terminator, only flag\",\n\t\t\tinput:      []string{\"test\", \"--flag\", \"x\"},\n\t\t\texpectFlag: \"x\",\n\t\t\texpectArgs: []string{},\n\t\t},\n\t\t{\n\t\t\tname:       \"flag defined after --\",\n\t\t\tinput:      []string{\"test\", \"--\", \"x\", \"--flag=value\"},\n\t\t\texpectFlag: \"\",\n\t\t\texpectArgs: []string{\"x\", \"--flag=value\"},\n\t\t},\n\t\t{\n\t\t\tname:       \"flag and without --\",\n\t\t\tinput:      []string{\"test\", \"--flag\", \"value\", \"x\"},\n\t\t\texpectFlag: \"value\",\n\t\t\texpectArgs: []string{\"x\"},\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvar flagVal string\n\t\t\tvar argsVal []string\n\n\t\t\t// build minimal command with a StringFlag \"flag\"\n\t\t\tcmd := &Command{\n\t\t\t\tName: \"test\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName:        \"flag\",\n\t\t\t\t\t\tUsage:       \"a string flag\",\n\t\t\t\t\t\tDestination: &flagVal,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\targsVal = c.Args().Slice()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(context.Background(), tc.input)\n\t\t\tif tc.expectErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tif err != nil {\n\t\t\t\t\tassert.Contains(t, strings.ToLower(err.Error()), strings.ToLower(tc.errorContain))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expectFlag, flagVal)\n\t\t\t\tassert.Equal(t, tc.expectArgs, argsVal)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TestBoolFlagTerminator tests the bool flag\nfunc TestBoolFlagTerminator(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tinput        []string\n\t\texpectFlag   bool\n\t\texpectArgs   []string\n\t\texpectErr    bool\n\t\terrorContain string\n\t}{\n\t\t/*{\n\t\t\tname:         \"bool flag with invalid non-bool value\",\n\t\t\tinput:        []string{\"test\", \"--flag\", \"x\", \"--\", \"test\", \"a1\", \"a2\", \"a3\"},\n\t\t\texpectErr:    true,\n\t\t\terrorContain: \"invalid syntax\",\n\t\t},*/\n\t\t{\n\t\t\tname:       \"bool flag omitted value defaults to true\",\n\t\t\tinput:      []string{\"test\", \"--flag\", \"--\", \"x\"},\n\t\t\texpectFlag: true,\n\t\t\texpectArgs: []string{\"x\"},\n\t\t},\n\t\t{\n\t\t\tname:       \"bool flag explicitly set to false\",\n\t\t\tinput:      []string{\"test\", \"--flag=false\", \"--\", \"x\"},\n\t\t\texpectFlag: false,\n\t\t\texpectArgs: []string{\"x\"},\n\t\t},\n\t\t{\n\t\t\tname:       \"bool flag defined after --\",\n\t\t\tinput:      []string{\"test\", \"--\", \"x\", \"--flag=true\"},\n\t\t\texpectFlag: false,\n\t\t\texpectArgs: []string{\"x\", \"--flag=true\"},\n\t\t},\n\t\t{\n\t\t\tname:       \"bool flag and without --\",\n\t\t\tinput:      []string{\"test\", \"--flag=true\", \"x\"},\n\t\t\texpectFlag: true,\n\t\t\texpectArgs: []string{\"x\"},\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvar flagVal bool\n\t\t\tvar argsVal []string\n\n\t\t\t// build minimal command with a BoolFlag \"flag\"\n\t\t\tcmd := &Command{\n\t\t\t\tName: \"test\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{\n\t\t\t\t\t\tName:        \"flag\",\n\t\t\t\t\t\tUsage:       \"a bool flag\",\n\t\t\t\t\t\tDestination: &flagVal,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\t\t\targsVal = c.Args().Slice()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(context.Background(), tc.input)\n\t\t\tif tc.expectErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tif err != nil {\n\t\t\t\t\tassert.Contains(t, strings.ToLower(err.Error()), strings.ToLower(tc.errorContain))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expectFlag, flagVal)\n\t\t\t\tassert.Equal(t, tc.expectArgs, argsVal)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TestSliceStringFlagParsing tests the StringSliceFlag\nfunc TestSliceStringFlagParsing(t *testing.T) {\n\tvar sliceVal []string\n\n\tcmdNoDelimiter := &Command{\n\t\tName: \"test\",\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{\n\t\t\t\tName:  \"flag\",\n\t\t\t\tUsage: \"a string slice flag without delimiter\",\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\tsliceVal = c.StringSlice(\"flag\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\t/*cmdWithDelimiter := &Command{\n\t\tName: \"test\",\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{\n\t\t\t\tName:      \"flag\",\n\t\t\t\tUsage:     \"a string slice flag with delimiter\",\n\t\t\t\tDelimiter: ':',\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, c *Command) error {\n\t\t\tsliceVal = c.StringSlice(\"flag\")\n\t\t\treturn nil\n\t\t},\n\t}*/\n\n\ttests := []struct {\n\t\tname         string\n\t\tcmd          *Command\n\t\tinput        []string\n\t\texpectSlice  []string\n\t\texpectErr    bool\n\t\terrorContain string\n\t}{\n\t\t{\n\t\t\tname:        \"single value without delimiter (no split)\",\n\t\t\tcmd:         cmdNoDelimiter,\n\t\t\tinput:       []string{\"test\", \"--flag\", \"x\"},\n\t\t\texpectSlice: []string{\"x\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"multiple values with comma (default split)\",\n\t\t\tcmd:         cmdNoDelimiter,\n\t\t\tinput:       []string{\"test\", \"--flag\", \"x,y\"},\n\t\t\texpectSlice: []string{\"x\", \"y\"},\n\t\t},\n\t\t/*{\n\t\t\tname:        \"Case 10: with delimiter specified ':'\",\n\t\t\tcmd:         cmdWithDelimiter,\n\t\t\tinput:       []string{\"test\", \"--flag\", \"x:y\"},\n\t\t\texpectSlice: []string{\"x\", \"y\"},\n\t\t},*/\n\t\t{\n\t\t\tname:        \"without delimiter specified, value remains unsplit\",\n\t\t\tcmd:         cmdNoDelimiter,\n\t\t\tinput:       []string{\"test\", \"--flag\", \"x:y\"},\n\t\t\texpectSlice: []string{\"x:y\"},\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\t// Reset sliceVal\n\t\tsliceVal = nil\n\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.cmd.Run(context.Background(), tc.input)\n\t\t\tif tc.expectErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tif err != nil {\n\t\t\t\t\tassert.Contains(t, strings.ToLower(err.Error()), strings.ToLower(tc.errorContain))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expectSlice, sliceVal)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestJSONExportCommand(t *testing.T) {\n\tcmd := buildExtendedTestCommand()\n\tcmd.Arguments = []Argument{\n\t\t&IntArgs{\n\t\t\tName: \"fooi\",\n\t\t},\n\t}\n\n\tout, err := json.Marshal(cmd)\n\trequire.NoError(t, err)\n\n\texpected := `{\n\t\t\"name\": \"greet\",\n\t\t\"aliases\": null,\n\t\t\"usage\": \"Some app\",\n\t\t\"usageText\": \"app [first_arg] [second_arg]\",\n\t\t\"argsUsage\": \"\",\n\t\t\"version\": \"\",\n\t\t\"description\": \"Description of the application.\",\n\t\t\"defaultCommand\": \"\",\n\t\t\"category\": \"\",\n\t\t\"commands\": [\n\t\t  {\n\t\t\t\"name\": \"config\",\n\t\t\t\"aliases\": [\n\t\t\t  \"c\"\n\t\t\t],\n\t\t\t\"usage\": \"another usage test\",\n\t\t\t\"usageText\": \"\",\n\t\t\t\"argsUsage\": \"\",\n\t\t\t\"version\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"defaultCommand\": \"\",\n\t\t\t\"category\": \"\",\n\t\t\t\"commands\": [\n\t\t\t  {\n\t\t\t\t\"name\": \"sub-config\",\n\t\t\t\t\"aliases\": [\n\t\t\t\t  \"s\",\n\t\t\t\t  \"ss\"\n\t\t\t\t],\n\t\t\t\t\"usage\": \"another usage test\",\n\t\t\t\t\"usageText\": \"\",\n\t\t\t\t\"argsUsage\": \"\",\n\t\t\t\t\"version\": \"\",\n\t\t\t\t\"description\": \"\",\n\t\t\t\t\"defaultCommand\": \"\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"commands\": null,\n\t\t\t\t\"flags\": [\n\t\t\t\t  {\n\t\t\t\t\t\"name\": \"sub-flag\",\n\t\t\t\t\t\"category\": \"\",\n\t\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\t\"usage\": \"\",\n\t\t\t\t\t\"required\": false,\n\t\t\t\t\t\"hidden\": false,\n\t\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\t\"local\": false,\n\t\t\t\t\t\"defaultValue\": \"\",\n\t\t\t\t\t\"aliases\": [\n\t\t\t\t\t  \"sub-fl\",\n\t\t\t\t\t  \"s\"\n\t\t\t\t\t],\n\t\t\t\t\t\"takesFileArg\": false,\n\t\t\t\t\t\"config\": {\n\t\t\t\t\t  \"TrimSpace\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\t\"validateDefaults\" : false\n\t\t\t\t  },\n\t\t\t\t  {\n\t\t\t\t\t\"name\": \"sub-command-flag\",\n\t\t\t\t\t\"category\": \"\",\n\t\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\t\"usage\": \"some usage text\",\n\t\t\t\t\t\"required\": false,\n\t\t\t\t\t\"hidden\": false,\n\t\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\t\"local\": false,\n\t\t\t\t\t\"defaultValue\": false,\n\t\t\t\t\t\"aliases\": [\n\t\t\t\t\t  \"s\"\n\t\t\t\t\t],\n\t\t\t\t\t\"takesFileArg\": false,\n\t\t\t\t\t\"config\": {\n\t\t\t\t\t  \"Count\": null\n\t\t\t\t\t},\n\t\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\t\"validateDefaults\" : false\n\t\t\t\t  }\n\t\t\t\t],\n\t\t\t\t\"hideHelp\": false,\n\t\t\t\t\"hideHelpCommand\": false,\n\t\t\t\t\"hideVersion\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"authors\": null,\n\t\t\t\t\"copyright\": \"\",\n\t\t\t\t\"metadata\": null,\n\t\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\t\"suggest\": false,\n\t\t\t\t\"allowExtFlags\": false,\n\t\t\t\t\"skipFlagParsing\": false,\n\t\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\t\"arguments\": null,\n\t\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\t\"stopOnNthArg\": null\n\t\t\t  }\n\t\t\t],\n\t\t\t\"flags\": [\n\t\t\t  {\n\t\t\t\t\"name\": \"flag\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\"usage\": \"\",\n\t\t\t\t\"required\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\"local\": false,\n\t\t\t\t\"defaultValue\": \"\",\n\t\t\t\t\"aliases\": [\n\t\t\t\t  \"fl\",\n\t\t\t\t  \"f\"\n\t\t\t\t],\n\t\t\t\t\"takesFileArg\": true,\n\t\t\t\t\"config\": {\n\t\t\t\t  \"TrimSpace\": false\n\t\t\t\t},\n\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\"validateDefaults\" : false\n\t\t\t  },\n\t\t\t  {\n\t\t\t\t\"name\": \"another-flag\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\"usage\": \"another usage text\",\n\t\t\t\t\"required\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\"local\": false,\n\t\t\t\t\"defaultValue\": false,\n\t\t\t\t\"aliases\": [\n\t\t\t\t  \"b\"\n\t\t\t\t],\n\t\t\t\t\"takesFileArg\": false,\n\t\t\t\t\"config\": {\n\t\t\t\t  \"Count\": null\n\t\t\t\t},\n\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\"validateDefaults\" : false\n\t\t\t  }\n\t\t\t],\n\t\t\t\"hideHelp\": false,\n\t\t\t\"hideHelpCommand\": false,\n\t\t\t\"hideVersion\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"authors\": null,\n\t\t\t\"copyright\": \"\",\n\t\t\t\"metadata\": null,\n\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\"suggest\": false,\n\t\t\t\"allowExtFlags\": false,\n\t\t\t\"skipFlagParsing\": false,\n\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\"arguments\": null,\n\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\"stopOnNthArg\": null\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"info\",\n\t\t\t\"aliases\": [\n\t\t\t  \"i\",\n\t\t\t  \"in\"\n\t\t\t],\n\t\t\t\"usage\": \"retrieve generic information\",\n\t\t\t\"usageText\": \"\",\n\t\t\t\"argsUsage\": \"\",\n\t\t\t\"version\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"defaultCommand\": \"\",\n\t\t\t\"category\": \"\",\n\t\t\t\"commands\": null,\n\t\t\t\"flags\": null,\n\t\t\t\"hideHelp\": false,\n\t\t\t\"hideHelpCommand\": false,\n\t\t\t\"hideVersion\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"authors\": null,\n\t\t\t\"copyright\": \"\",\n\t\t\t\"metadata\": null,\n\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\"suggest\": false,\n\t\t\t\"allowExtFlags\": false,\n\t\t\t\"skipFlagParsing\": false,\n\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\"arguments\": null,\n\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\"stopOnNthArg\": null\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"some-command\",\n\t\t\t\"aliases\": null,\n\t\t\t\"usage\": \"\",\n\t\t\t\"usageText\": \"\",\n\t\t\t\"argsUsage\": \"\",\n\t\t\t\"version\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"defaultCommand\": \"\",\n\t\t\t\"category\": \"\",\n\t\t\t\"commands\": null,\n\t\t\t\"flags\": null,\n\t\t\t\"hideHelp\": false,\n\t\t\t\"hideHelpCommand\": false,\n\t\t\t\"hideVersion\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"authors\": null,\n\t\t\t\"copyright\": \"\",\n\t\t\t\"metadata\": null,\n\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\"suggest\": false,\n\t\t\t\"allowExtFlags\": false,\n\t\t\t\"skipFlagParsing\": false,\n\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\"arguments\": null,\n\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\"stopOnNthArg\": null\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"hidden-command\",\n\t\t\t\"aliases\": null,\n\t\t\t\"usage\": \"\",\n\t\t\t\"usageText\": \"\",\n\t\t\t\"argsUsage\": \"\",\n\t\t\t\"version\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"defaultCommand\": \"\",\n\t\t\t\"category\": \"\",\n\t\t\t\"commands\": null,\n\t\t\t\"flags\": [\n\t\t\t  {\n\t\t\t\t\"name\": \"completable\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\"usage\": \"\",\n\t\t\t\t\"required\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\"local\": false,\n\t\t\t\t\"defaultValue\": false,\n\t\t\t\t\"aliases\": null,\n\t\t\t\t\"takesFileArg\": false,\n\t\t\t\t\"config\": {\n\t\t\t\t  \"Count\": null\n\t\t\t\t},\n\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\"validateDefaults\": false\n\t\t\t  }\n\t\t\t],\n\t\t\t\"hideHelp\": false,\n\t\t\t\"hideHelpCommand\": false,\n\t\t\t\"hideVersion\": false,\n\t\t\t\"hidden\": true,\n\t\t\t\"authors\": null,\n\t\t\t\"copyright\": \"\",\n\t\t\t\"metadata\": null,\n\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\"suggest\": false,\n\t\t\t\"allowExtFlags\": false,\n\t\t\t\"skipFlagParsing\": false,\n\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\"arguments\": null,\n\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\"stopOnNthArg\": null\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"usage\",\n\t\t\t\"aliases\": [\n\t\t\t  \"u\"\n\t\t\t],\n\t\t\t\"usage\": \"standard usage text\",\n\t\t\t\"usageText\": \"\\nUsage for the usage text\\n- formatted:  Based on the specified ConfigMap and summon secrets.yml\\n- list:       Inspect the environment for a specific process running on a Pod\\n- for_effect: Compare 'namespace' environment with 'local'\\n\\n` + \"```\\\\nfunc() { ... }\\\\n```\" + `\\n\\nShould be a part of the same code block\\n\",\n\t\t\t\"argsUsage\": \"\",\n\t\t\t\"version\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"defaultCommand\": \"\",\n\t\t\t\"category\": \"\",\n\t\t\t\"commands\": [\n\t\t\t  {\n\t\t\t\t\"name\": \"sub-usage\",\n\t\t\t\t\"aliases\": [\n\t\t\t\t  \"su\"\n\t\t\t\t],\n\t\t\t\t\"usage\": \"standard usage text\",\n\t\t\t\t\"usageText\": \"Single line of UsageText\",\n\t\t\t\t\"argsUsage\": \"\",\n\t\t\t\t\"version\": \"\",\n\t\t\t\t\"description\": \"\",\n\t\t\t\t\"defaultCommand\": \"\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"commands\": null,\n\t\t\t\t\"flags\": [\n\t\t\t\t  {\n\t\t\t\t\t\"name\": \"sub-command-flag\",\n\t\t\t\t\t\"category\": \"\",\n\t\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\t\"usage\": \"some usage text\",\n\t\t\t\t\t\"required\": false,\n\t\t\t\t\t\"hidden\": false,\n\t\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\t\"local\": false,\n\t\t\t\t\t\"defaultValue\": false,\n\t\t\t\t\t\"aliases\": [\n\t\t\t\t\t  \"s\"\n\t\t\t\t\t],\n\t\t\t\t\t\"takesFileArg\": false,\n\t\t\t\t\t\"config\": {\n\t\t\t\t\t  \"Count\": null\n\t\t\t\t\t},\n\t\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\t\"validateDefaults\" : false\n\t\t\t\t  }\n\t\t\t\t],\n\t\t\t\t\"hideHelp\": false,\n\t\t\t\t\"hideHelpCommand\": false,\n\t\t\t\t\"hideVersion\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"authors\": null,\n\t\t\t\t\"copyright\": \"\",\n\t\t\t\t\"metadata\": null,\n\t\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\t\"suggest\": false,\n\t\t\t\t\"allowExtFlags\": false,\n\t\t\t\t\"skipFlagParsing\": false,\n\t\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\t\"arguments\": null,\n\t\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\t\"stopOnNthArg\": null\n\t\t\t  }\n\t\t\t],\n\t\t\t\"flags\": [\n\t\t\t  {\n\t\t\t\t\"name\": \"flag\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\"usage\": \"\",\n\t\t\t\t\"required\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\"local\": false,\n\t\t\t\t\"defaultValue\": \"\",\n\t\t\t\t\"aliases\": [\n\t\t\t\t  \"fl\",\n\t\t\t\t  \"f\"\n\t\t\t\t],\n\t\t\t\t\"takesFileArg\": true,\n\t\t\t\t\"config\": {\n\t\t\t\t  \"TrimSpace\": false\n\t\t\t\t},\n\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\"validateDefaults\" : false\n\t\t\t  },\n\t\t\t  {\n\t\t\t\t\"name\": \"another-flag\",\n\t\t\t\t\"category\": \"\",\n\t\t\t\t\"defaultText\": \"\",\n\t\t\t\t\"usage\": \"another usage text\",\n\t\t\t\t\"required\": false,\n\t\t\t\t\"hidden\": false,\n\t\t\t\t\"hideDefault\": false,\n\t\t\t\t\"local\": false,\n\t\t\t\t\"defaultValue\": false,\n\t\t\t\t\"aliases\": [\n\t\t\t\t  \"b\"\n\t\t\t\t],\n\t\t\t\t\"takesFileArg\": false,\n\t\t\t\t\"config\": {\n\t\t\t\t  \"Count\": null\n\t\t\t\t},\n\t\t\t\t\"onlyOnce\": false,\n\t\t\t\t\"validateDefaults\" : false\n\t\t\t  }\n\t\t\t],\n\t\t\t\"hideHelp\": false,\n\t\t\t\"hideHelpCommand\": false,\n\t\t\t\"hideVersion\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"authors\": null,\n\t\t\t\"copyright\": \"\",\n\t\t\t\"metadata\": null,\n\t\t\t\"sliceFlagSeparator\": \"\",\n\t\t\t\"disableSliceFlagSeparator\": false,\n\t\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\t\"useShortOptionHandling\": false,\n\t\t\t\"suggest\": false,\n\t\t\t\"allowExtFlags\": false,\n\t\t\t\"skipFlagParsing\": false,\n\t\t\t\"prefixMatchCommands\": false,\n\t\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\t\"arguments\": null,\n\t\t\t\"readArgsFromStdin\": false,\n\t\t\t\"stopOnNthArg\": null\n\t\t  }\n\t\t],\n\t\t\"flags\": [\n\t\t  {\n\t\t\t\"name\": \"socket\",\n\t\t\t\"category\": \"\",\n\t\t\t\"defaultText\": \"\",\n\t\t\t\"usage\": \"some 'usage' text\",\n\t\t\t\"required\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"hideDefault\": false,\n\t\t\t\"local\": false,\n\t\t\t\"defaultValue\": \"value\",\n\t\t\t\"aliases\": [\n\t\t\t  \"s\"\n\t\t\t],\n\t\t\t\"takesFileArg\": true,\n\t\t\t\"config\": {\n\t\t\t  \"TrimSpace\": false\n\t\t\t},\n\t\t\t\"onlyOnce\": false,\n\t\t\t\"validateDefaults\" : false\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"flag\",\n\t\t\t\"category\": \"\",\n\t\t\t\"defaultText\": \"\",\n\t\t\t\"usage\": \"\",\n\t\t\t\"required\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"hideDefault\": false,\n\t\t\t\"local\": false,\n\t\t\t\"defaultValue\": \"\",\n\t\t\t\"aliases\": [\n\t\t\t  \"fl\",\n\t\t\t  \"f\"\n\t\t\t],\n\t\t\t\"takesFileArg\": false,\n\t\t\t\"config\": {\n\t\t\t  \"TrimSpace\": false\n\t\t\t},\n\t\t\t\"onlyOnce\": false,\n\t\t\t\"validateDefaults\" : false\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"another-flag\",\n\t\t\t\"category\": \"\",\n\t\t\t\"defaultText\": \"\",\n\t\t\t\"usage\": \"another usage text\",\n\t\t\t\"required\": false,\n\t\t\t\"hidden\": false,\n\t\t\t\"hideDefault\": false,\n\t\t\t\"local\": false,\n\t\t\t\"defaultValue\": false,\n\t\t\t\"aliases\": [\n\t\t\t  \"b\"\n\t\t\t],\n\t\t\t\"takesFileArg\": false,\n\t\t\t\"config\": {\n\t\t\t  \"Count\": null\n\t\t\t},\n\t\t\t\"onlyOnce\": false,\n\t\t\t\"validateDefaults\" : false\n\t\t  },\n\t\t  {\n\t\t\t\"name\": \"hidden-flag\",\n\t\t\t\"category\": \"\",\n\t\t\t\"defaultText\": \"\",\n\t\t\t\"usage\": \"\",\n\t\t\t\"required\": false,\n\t\t\t\"hidden\": true,\n\t\t\t\"hideDefault\": false,\n\t\t\t\"local\": false,\n\t\t\t\"defaultValue\": false,\n\t\t\t\"aliases\": null,\n\t\t\t\"takesFileArg\": false,\n\t\t\t\"config\": {\n\t\t\t  \"Count\": null\n\t\t\t},\n\t\t\t\"onlyOnce\": false,\n\t\t\t\"validateDefaults\" : false\n\t\t  }\n\t\t],\n\t\t\"hideHelp\": false,\n\t\t\"hideHelpCommand\": false,\n\t\t\"hideVersion\": false,\n\t\t\"hidden\": false,\n\t\t\"authors\": [\n\t\t  \"Harrison <harrison@lolwut.example.com>\",\n\t\t  {\n\t\t\t\"Name\": \"Oliver Allen\",\n\t\t\t\"Address\": \"oliver@toyshop.com\"\n\t\t  }\n\t\t],\n\t\t\"copyright\": \"\",\n\t\t\"metadata\": null,\n\t\t\"sliceFlagSeparator\": \"\",\n\t\t\"disableSliceFlagSeparator\": false,\n\t\t\"mapFlagKeyValueSeparator\": \"\",\n\t\t\"useShortOptionHandling\": false,\n\t\t\"suggest\": false,\n\t\t\"allowExtFlags\": false,\n\t\t\"skipFlagParsing\": false,\n\t\t\"prefixMatchCommands\": false,\n\t\t\"mutuallyExclusiveFlags\": null,\n\t\t\"arguments\": [\n\t\t  {\n\t\t\t\"name\": \"fooi\",\n\t\t\t\"value\": 0,\n\t\t\t\"usageText\": \"\",\n\t\t\t\"minTimes\": 0,\n\t\t\t\"maxTimes\": 0,\n\t\t\t\"config\": {\n\t\t\t  \"Base\": 0\n\t\t\t}\n\t\t  }\n\t\t],\n\t\t\"readArgsFromStdin\": false,\n\t\t\"stopOnNthArg\": null\n\t  }\n`\n\tassert.JSONEq(t, expected, string(out))\n}\n\nfunc TestCommand_ExclusiveFlags(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"foo1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"foo2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"bar\", \"--foo1\", \"var1\", \"--foo2\", \"var2\"})\n\n\trequire.Equal(t, \"option foo1 cannot be set along with option foo2\", err.Error())\n}\n\nfunc TestCommand_ExclusiveFlagsWithOnUsageError(t *testing.T) {\n\texpectedErr := errors.New(\"my custom error\")\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"foo1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"foo2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tOnUsageError: func(_ context.Context, _ *Command, _ error, _ bool) error {\n\t\t\treturn expectedErr\n\t\t},\n\t}\n\n\tactualErr := cmd.Run(buildTestContext(t), []string{\"bar\", \"--foo1\", \"v1\", \"--foo2\", \"v2\"})\n\n\trequire.ErrorIs(t, actualErr, expectedErr)\n}\n\nfunc TestCommand_ExclusiveFlagsWithAfter(t *testing.T) {\n\tvar called bool\n\tcmd := &Command{\n\t\tName: \"bar\",\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tCategory: \"cat1\",\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"foo2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAfter: func(ctx context.Context, cmd *Command) error {\n\t\t\tcalled = true\n\t\t\treturn nil\n\t\t},\n\t}\n\n\trequire.Error(t, cmd.Run(buildTestContext(t), []string{\n\t\t\"bar\",\n\t\t\"--foo\", \"v1\",\n\t\t\"--foo2\", \"v2\",\n\t}))\n\trequire.True(t, called)\n}\n\nfunc TestCommand_ParallelRun(t *testing.T) {\n\tt.Parallel()\n\n\tfor i := 0; i < 10; i++ {\n\t\tt.Run(fmt.Sprintf(\"run_%d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tt.Errorf(\"unexpected panic - '%s'\", r)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:  \"debug\",\n\t\t\t\tUsage: \"make an explosive entrance\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tif err := cmd.Run(context.Background(), nil); err != nil {\n\t\t\t\tfmt.Printf(\"%s\\n\", err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_ExclusiveFlagsPersistent(t *testing.T) {\n\texclusiveGroup := func(flags ...string) []MutuallyExclusiveFlags {\n\t\tgrp := MutuallyExclusiveFlags{}\n\t\tfor _, name := range flags {\n\t\t\tgrp.Flags = append(grp.Flags, []Flag{&StringFlag{Name: name}})\n\t\t}\n\t\treturn []MutuallyExclusiveFlags{grp}\n\t}\n\n\tnoop := func(_ context.Context, _ *Command) error { return nil }\n\n\tnewBaseCmd := func() *Command {\n\t\treturn &Command{\n\t\t\tName:                   \"root\",\n\t\t\tMutuallyExclusiveFlags: exclusiveGroup(\"alpha\", \"beta\"),\n\t\t\tCommands:               []*Command{{Name: \"sub\", Action: noop}},\n\t\t}\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\tsetup   func() *Command\n\t\targs    []string\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:  \"single flag propagated to subcommand\",\n\t\t\tsetup: newBaseCmd,\n\t\t\targs:  []string{\"root\", \"sub\", \"--alpha\", \"hello\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"both exclusive flags on subcommand errors\",\n\t\t\tsetup:   newBaseCmd,\n\t\t\targs:    []string{\"root\", \"sub\", \"--alpha\", \"hello\", \"--beta\", \"world\"},\n\t\t\twantErr: \"cannot be set along with\",\n\t\t},\n\t\t{\n\t\t\tname:  \"neither flag set without required is ok\",\n\t\t\tsetup: newBaseCmd,\n\t\t\targs:  []string{\"root\", \"sub\"},\n\t\t},\n\t\t{\n\t\t\tname: \"exclusive flags checked on grandchild\",\n\t\t\tsetup: func() *Command {\n\t\t\t\tcmd := newBaseCmd()\n\t\t\t\tsub := cmd.Commands[0]\n\t\t\t\tsub.Name = \"mid\"\n\t\t\t\tsub.Action = nil\n\t\t\t\tsub.Commands = []*Command{{Name: \"leaf\", Action: noop}}\n\t\t\t\treturn cmd\n\t\t\t},\n\t\t\targs:    []string{\"root\", \"mid\", \"leaf\", \"--alpha\", \"hello\", \"--beta\", \"world\"},\n\t\t\twantErr: \"cannot be set along with\",\n\t\t},\n\t\t{\n\t\t\tname: \"subcommand own group checked alongside parent group\",\n\t\t\tsetup: func() *Command {\n\t\t\t\tcmd := newBaseCmd()\n\t\t\t\tcmd.Commands[0].MutuallyExclusiveFlags = exclusiveGroup(\"gamma\", \"delta\")\n\t\t\t\treturn cmd\n\t\t\t},\n\t\t\targs:    []string{\"root\", \"sub\", \"--gamma\", \"hello\", \"--delta\", \"world\"},\n\t\t\twantErr: \"cannot be set along with\",\n\t\t},\n\t\t{\n\t\t\tname: \"parent group violation detected when subcommand has own group\",\n\t\t\tsetup: func() *Command {\n\t\t\t\tcmd := newBaseCmd()\n\t\t\t\tcmd.Commands[0].MutuallyExclusiveFlags = exclusiveGroup(\"gamma\", \"delta\")\n\t\t\t\treturn cmd\n\t\t\t},\n\t\t\targs:    []string{\"root\", \"sub\", \"--alpha\", \"hello\", \"--beta\", \"world\"},\n\t\t\twantErr: \"cannot be set along with\",\n\t\t},\n\t\t{\n\t\t\tname: \"parent and subcommand groups both pass independently\",\n\t\t\tsetup: func() *Command {\n\t\t\t\tcmd := newBaseCmd()\n\t\t\t\tcmd.Commands[0].MutuallyExclusiveFlags = exclusiveGroup(\"gamma\", \"delta\")\n\t\t\t\treturn cmd\n\t\t\t},\n\t\t\targs: []string{\"root\", \"sub\", \"--alpha\", \"hello\", \"--gamma\", \"world\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.setup().Run(buildTestContext(t), tt.args)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErr)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "completion.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"embed\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\nconst (\n\tcompletionCommandName = \"completion\"\n\n\t// This flag is supposed to only be used by the completion script itself to generate completions on the fly.\n\tcompletionFlag = \"--generate-shell-completion\"\n)\n\ntype renderCompletion func(cmd *Command, appName string) (string, error)\n\nvar (\n\t//go:embed autocomplete\n\tautoCompleteFS embed.FS\n\n\tshellCompletions = map[string]renderCompletion{\n\t\t\"bash\": func(c *Command, appName string) (string, error) {\n\t\t\tb, err := autoCompleteFS.ReadFile(\"autocomplete/bash_autocomplete\")\n\t\t\treturn fmt.Sprintf(string(b), appName), err\n\t\t},\n\t\t\"zsh\": func(c *Command, appName string) (string, error) {\n\t\t\tb, err := autoCompleteFS.ReadFile(\"autocomplete/zsh_autocomplete\")\n\t\t\treturn fmt.Sprintf(string(b), appName), err\n\t\t},\n\t\t\"fish\": func(c *Command, appName string) (string, error) {\n\t\t\tb, err := autoCompleteFS.ReadFile(\"autocomplete/fish_autocomplete\")\n\t\t\treturn fmt.Sprintf(string(b), appName), err\n\t\t},\n\t\t\"pwsh\": func(c *Command, appName string) (string, error) {\n\t\t\tb, err := autoCompleteFS.ReadFile(\"autocomplete/powershell_autocomplete.ps1\")\n\t\t\treturn string(b), err\n\t\t},\n\t}\n)\n\nconst completionDescription = `Output shell completion script for bash, zsh, fish, or Powershell.\nSource the output to enable completion.\n\n# .bashrc\nsource <($COMMAND completion bash)\n\n# .zshrc\nsource <($COMMAND completion zsh)\n\n# fish\n$COMMAND completion fish > ~/.config/fish/completions/$COMMAND.fish\n\n# Powershell\nOutput the script to path/to/autocomplete/$COMMAND.ps1 an run it.\n`\n\nfunc buildCompletionCommand(appName string) *Command {\n\treturn &Command{\n\t\tName:        completionCommandName,\n\t\tHidden:      true,\n\t\tUsage:       \"Output shell completion script for bash, zsh, fish, or Powershell\",\n\t\tDescription: strings.ReplaceAll(completionDescription, \"$COMMAND\", appName),\n\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\treturn printShellCompletion(ctx, cmd, appName)\n\t\t},\n\t\tisCompletionCommand: true,\n\t}\n}\n\nfunc printShellCompletion(_ context.Context, cmd *Command, appName string) error {\n\tvar shells []string\n\tfor k := range shellCompletions {\n\t\tshells = append(shells, k)\n\t}\n\n\tsort.Strings(shells)\n\n\tif cmd.Args().Len() == 0 {\n\t\treturn Exit(fmt.Sprintf(\"no shell provided for completion command. available shells are %+v\", shells), 1)\n\t}\n\ts := cmd.Args().First()\n\n\trenderCompletion, ok := shellCompletions[s]\n\tif !ok {\n\t\treturn Exit(fmt.Sprintf(\"unknown shell %s, available shells are %+v\", s, shells), 1)\n\t}\n\n\tcompletionScript, err := renderCompletion(cmd, appName)\n\tif err != nil {\n\t\treturn Exit(err, 1)\n\t}\n\n\t_, err = cmd.Writer.Write([]byte(completionScript))\n\tif err != nil {\n\t\treturn Exit(err, 1)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "completion_test.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCompletionDisable(t *testing.T) {\n\tcmd := &Command{}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", completionCommandName})\n\tassert.Error(t, err, \"Expected error for no help topic for completion\")\n}\n\nfunc TestCompletionEnable(t *testing.T) {\n\tcmd := &Command{\n\t\tEnableShellCompletion: true,\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:     \"goo\",\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", completionCommandName})\n\tassert.ErrorContains(t, err, \"no shell provided\")\n}\n\nfunc TestCompletionEnableDiffCommandName(t *testing.T) {\n\tcmd := &Command{\n\t\tEnableShellCompletion:      true,\n\t\tShellCompletionCommandName: \"junky\",\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"junky\"})\n\tassert.ErrorContains(t, err, \"no shell provided\")\n}\n\nfunc TestCompletionShell(t *testing.T) {\n\tfor k := range shellCompletions {\n\t\tout := &bytes.Buffer{}\n\n\t\tt.Run(k, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tEnableShellCompletion: true,\n\t\t\t\tWriter:                out,\n\t\t\t}\n\n\t\t\tr := require.New(t)\n\n\t\t\tr.NoError(cmd.Run(buildTestContext(t), []string{\"foo\", completionCommandName, k}))\n\t\t\tr.Containsf(\n\t\t\t\tk, out.String(),\n\t\t\t\t\"Expected output to contain shell name %[1]q\", k,\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc TestCompletionSubcommand(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\targs        []string\n\t\tcontains    string\n\t\tmsg         string\n\t\tmsgArgs     []interface{}\n\t\tnotContains bool\n\t}{\n\t\t{\n\t\t\tname:     \"subcommand general completion\",\n\t\t\targs:     []string{\"foo\", \"bar\", completionFlag},\n\t\t\tcontains: \"xyz\",\n\t\t\tmsg:      \"Expected output to contain shell name %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"xyz\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"subcommand flag completion\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"-\", completionFlag},\n\t\t\tcontains: \"l1\",\n\t\t\tmsg:      \"Expected output to contain shell name %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"l1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"subcommand flag no completion\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"--\", completionFlag},\n\t\t\tcontains: \"l1\",\n\t\t\tmsg:      \"Expected output to contain shell name %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"l1\",\n\t\t\t},\n\t\t\tnotContains: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"sub sub command general completion\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"xyz\", completionFlag},\n\t\t\tcontains: \"-g\",\n\t\t\tmsg:      \"Expected output to contain flag %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"-g\",\n\t\t\t},\n\t\t\tnotContains: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"sub sub command flag completion\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"xyz\", \"-\", completionFlag},\n\t\t\tcontains: \"-g\",\n\t\t\tmsg:      \"Expected output to contain flag %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"-g\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"sub sub command no completion\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"xyz\", \"--\", completionFlag},\n\t\t\tcontains: \"-g\",\n\t\t\tmsg:      \"Expected output to contain flag %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"-g\",\n\t\t\t},\n\t\t\tnotContains: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"sub sub command no completion extra args\",\n\t\t\targs:     []string{\"foo\", \"bar\", \"xyz\", \"--\", \"sargs\", completionFlag},\n\t\t\tcontains: \"-g\",\n\t\t\tmsg:      \"Expected output to contain flag %[1]q\",\n\t\t\tmsgArgs: []interface{}{\n\t\t\t\t\"-g\",\n\t\t\t},\n\t\t\tnotContains: true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tout := &bytes.Buffer{}\n\n\t\t\tcmd := &Command{\n\t\t\t\tEnableShellCompletion: true,\n\t\t\t\tWriter:                out,\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"bar\",\n\t\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\t\tName: \"l1\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction: func(ctx context.Context, c *Command) error { return nil },\n\t\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"xyz\",\n\t\t\t\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\t\t\t\tName: \"g\",\n\t\t\t\t\t\t\t\t\t\tAliases: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"t\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tAction: func(ctx context.Context, c *Command) error { return nil },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tr := require.New(t)\n\n\t\t\tr.NoError(cmd.Run(buildTestContext(t), test.args))\n\t\t\tif test.notContains {\n\t\t\t\tr.NotContainsf(out.String(), test.contains, test.msg, test.msgArgs...)\n\t\t\t} else {\n\t\t\t\tr.Containsf(out.String(), test.contains, test.msg, test.msgArgs...)\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype mockWriter struct {\n\terr error\n}\n\nfunc (mw *mockWriter) Write(p []byte) (int, error) {\n\tif mw.err != nil {\n\t\treturn 0, mw.err\n\t}\n\treturn len(p), nil\n}\n\nfunc TestCompletionInvalidShell(t *testing.T) {\n\tcmd := &Command{\n\t\tEnableShellCompletion: true,\n\t}\n\n\tunknownShellName := \"junky-sheell\"\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", completionCommandName, unknownShellName})\n\tassert.ErrorContains(t, err, \"unknown shell junky-sheell\")\n\n\tenableError := true\n\tshellCompletions[unknownShellName] = func(c *Command, appName string) (string, error) {\n\t\tif enableError {\n\t\t\treturn \"\", fmt.Errorf(\"cant do completion\")\n\t\t}\n\t\treturn \"something\", nil\n\t}\n\tdefer func() {\n\t\tdelete(shellCompletions, unknownShellName)\n\t}()\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", completionCommandName, unknownShellName})\n\tassert.ErrorContains(t, err, \"cant do completion\")\n\n\t// now disable shell completion error\n\tenableError = false\n\tc := cmd.Command(completionCommandName)\n\tassert.NotNil(t, c)\n\tc.Writer = &mockWriter{\n\t\terr: fmt.Errorf(\"writer error\"),\n\t}\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", completionCommandName, unknownShellName})\n\tassert.ErrorContains(t, err, \"writer error\")\n}\n"
  },
  {
    "path": "docs/CHANGELOG.md",
    "content": "> :warning: This document is no longer being actively maintained. Please see the\n> [releases page](https://github.com/urfave/cli/releases) for all release notes\n> and related hypermedia for releases `>= 1.22.5`, `>= 2.3.0`.\n\n---\n\n# Change Log\n\n**ATTN**: This project uses [semantic versioning](https://semver.org/).\n\n## Unreleased - 2.X series\n\nView [unreleased 2.X] series changes.\n\n## [2.2.0] - 2020-03-08\n\nThese release notes were written for the git hash [d648edd48d89ef3a841b1ec75c2ebbd4de5f748f](https://github.com/urfave/cli/tree/d648edd48d89ef3a841b1ec75c2ebbd4de5f748f)\n\n### Fixed\n\n* Fixed zsh completion scripts in [urfave/cli/pull/1062](https://github.com/urfave/cli/pull/1062) via [@zhsj](https://github.com/zhsj)\n* Fixed description of subcommand to be more consistent in [urfave/cli/pull/1054](https://github.com/urfave/cli/pull/1054) via [@itchyny](https://github.com/itchyny)\n* Fixed possible runtime panic in slice parsing in [urfave/cli/pull/1049](https://github.com/urfave/cli/pull/1049) via [@saschagrunert](https://github.com/saschagrunert)\n* Fixed invalid man page header generation in [urfave/cli/pull/1041](https://github.com/urfave/cli/pull/1041) via [@saschagrunert](https://github.com/saschagrunert)\n\n### Changed\n\n* Improved auto-completion instructions and added example gifs in [urfave/cli/pull/1059](https://github.com/urfave/cli/pull/1059) via [@masonj188](https://github.com/masonj188)\n* Removed the author from generated man pages in [urfave/cli/pull/1041](https://github.com/urfave/cli/pull/1041) via [@saschagrunert](https://github.com/saschagrunert)\n\n### Added\n\n* Added destination field to `StringSliceFlag` in [urfave/cli/pull/1078](https://github.com/urfave/cli/pull/1078) via [@davidsbond](https://github.com/davidsbond)\n* Added `HideHelpCommand`. While `HideHelp` hides both `help` command and `--help` flag, `HideHelpCommand` only hides `help` command and leave `--help` flag as-is in [urfave/cli/pull/1083](https://github.com/urfave/cli/pull/1083) via [@AkihiroSuda](https://github.com/AkihiroSuda)\n* Added timestampFlag docs in [urfave/cli/pull/997](https://github.com/urfave/cli/pull/997) via [@drov0](https://github.com/drov0)\n* Added required flags documentation in [urfave/cli/pull/1008](https://github.com/urfave/cli/pull/1008) via [@lynncyrin](https://github.com/lynncyrin), [@anberns](https://github.com/anberns)\n\n## [2.1.1] - 2019-12-24\n\n### Fixed\n\n* Fixed a `Context` regression introduced in `v2.1.0` in [urfave/cli/pull/1014](https://github.com/urfave/cli/pull/1014) via [@lynncyrin](https://github.com/lynncyrin)\n\n## [2.1.0] - 2019-12-24\n\nThese release notes were written for the git hash [ae84df4cef4a2a6f1a0cb1d41ea0f3af8755e5a8](https://github.com/urfave/cli/tree/ae84df4cef4a2a6f1a0cb1d41ea0f3af8755e5a8)\n\n### Fixed\n\n* Fixed some golint errors in [urfave/cli/pull/988](https://github.com/urfave/cli/pull/988) via [@liamchampton](https://github.com/liamchampton)\n* Fixed a panic with flag completion [urfave/cli/pull/946](https://github.com/urfave/cli/pull/946) via [@unRob](https://github.com/unRob)\n\n### Changed\n\n* Changed docs generation to use visible flags in [urfave/cli/pull/999](https://github.com/urfave/cli/pull/999) via [@subpop](https://github.com/subpop)\n* Changed `App.Run` to use an optional context for timeouts and cancellation in [urfave/cli/pull/975](https://github.com/urfave/cli/pull/975) via [@marwan-at-work](https://github.com/marwan-at-work)\n* Changed version info to be hidden if the user has not defined a version in [urfave/cli/pull/955](https://github.com/urfave/cli/pull/955) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n* Changed docs generation to take into account multiple authors in [urfave/cli/pull/900](https://github.com/urfave/cli/pull/900) via [@saschagrunert](https://github.com/saschagrunert)\n* Changed context to expose a `Value` accessor in [urfave/cli/pull/741](https://github.com/urfave/cli/pull/741) via [@corruptmemory](https://github.com/corruptmemory)\n\n### Added\n\n* Added timestamp flag in [urfave/cli/pull/987](https://github.com/urfave/cli/pull/987) via [@drov0](https://github.com/drov0)\n\n## [2.0.0] - 2019-11-17\n\nThe V2 changes were all shipped in [urfave/cli/pull/892](https://github.com/urfave/cli/pull/892), which was created with the effort of over a dozen participants! They are:\n\n[@asahasrabuddhe](https://github.com/asahasrabuddhe), [@meatballhat](https://github.com/meatballhat), [@jszwedko](https://github.com/jszwedko), [@lynncyrin](https://github.com/lynncyrin), [@AudriusButkevicius](https://github.com/AudriusButkevicius), [@saschagrunert](https://github.com/saschagrunert), [@rliebz](https://github.com/rliebz), [@johnweldon](https://github.com/johnweldon), [@nlewo](https://github.com/nlewo), [@grubernaut](https://github.com/grubernaut), [@OneOfOne](https://github.com/OneOfOne), [@VMitov](https://github.com/VMitov), [@cbranch](https://github.com/cbranch), [@marwan-at-work](https://github.com/marwan-at-work), [@uudashr](https://github.com/uudashr), [@bfreis](https://github.com/bfreis)\n\n### Added\n\n- Added `NewStringSlice` and `NewIntSlice` for creating their related types\n- Added `Float64SliceFlag` for unmarshaling a list of floats from the user\n- Added `Context.Lineage` to get all contexts from current up to global\n- Added `Context.LocalFlagNames` to get the flag names from *only* the current context\n- Added `BoolFlag.Value` to handle both default-false and default-true\n- Added `IsSet` method to the `Flag` interface which allows us to detect whether or not a flag has been set\n\n### Changed\n\n- `Context.FlagNames` now returns all flags in the context lineage\n- `Context.IsSet` now considers the full context lineage\n\n### Removed\n\n- Removed the ability to specify `&StringSlice{...string}` or `&IntSlice{...int}`.\n- Removed adapter code for deprecated `Action` func signature\n- Deprecated `App.Author`, `App.Email`, and `Command.ShortName` fields\n- Removed all `Context.Global*` methods, as the non-global versions now traverse up\n  the context lineage automatically.\n- Removed `Context.Parent` method, as this is now available via `Context.Lineage`\n- Removed `BoolTFlag` and related code, as this is now available via `BoolFlag.Value`\n\n## Unreleased - 1.22.X series\n\nView [unreleased 1.22.X] series changes.\n\n## [1.22.4] - 2020-03-31\n\n### Fixed\n\n- Fixed a panic with flag completion in [urfave/cli/pull/1101](https://github.com/urfave/cli/pull/1101) via [@unRob](https://github.com/unRob), [@VirrageS](https://github.com/VirrageS)\n\n## [1.22.3] - 2020-02-25\n\n### Fixed\n\n- String flag no longer persists the default value if the flag is explicitly initialized in [urfave/cli/pull/981](https://github.com/urfave/cli/pull/981) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n- `context.IsSet()` returns `true` or `false` correctly regardless of whether the short name or the full name of the flag is passed to it in [urfave/cli/pull/978](https://github.com/urfave/cli/pull/978) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n- Hide version if the version is not set by the user in [urfave/cli/pull/954](https://github.com/urfave/cli/pull/954) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n\n## [1.22.2] - 2019-11-17\n\n### Fixed\n\n- Fix v1.21.0 pass through regression in [urfave/cli/pull/872](https://github.com/urfave/cli/pull/872) via [@lynncyrin](https://github.com/lynncyrin)\n- Fix infinite loop when parsing invalid flags for apps with short option handling in [urfave/cli/pull/911](https://github.com/urfave/cli/pull/911) via [@rliebz](https://github.com/rliebz)\n- Fix zsh autocomplete in [urfave/cli/pull/906](https://github.com/urfave/cli/pull/906) via [@gnowxilef](https://github.com/gnowxilef)\n- Fix typo in `DocGenerationFlag.TakesValue()` docstring in [urfave/cli/pull/902](https://github.com/urfave/cli/pull/902) via [@benmoose](https://github.com/benmoose)\n- Avoid panic for missing flag value in [urfave/cli/pull/893](https://github.com/urfave/cli/pull/893) via [@rliebz](https://github.com/rliebz)\n\n### Changed\n\n- Simplify `HelpPrinter` and `CustomHelpPrinter` behaviors in [urfave/cli/pull/912](https://github.com/urfave/cli/pull/912) via [@rliebz](https://github.com/rliebz)\n\n## [1.22.1] - 2019-09-11\n\n### Fixed\n\n* Hide output of hidden commands on man pages in [urfave/cli/pull/889](https://github.com/urfave/cli/pull/889) via [@crosbymichael](https://github.com/crosbymichael)\n* Don't generate fish completion for hidden commands [urfave/cli/pull/891](https://github.com/urfave/891) via [@saschagrunert](https://github.com/saschagrunert)\n* Using short flag names for required flags throws an error in [urfave/cli/pull/890](https://github.com/urfave/cli/pull/890) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n\n### Changed\n\n* Remove flag code generation logic, legacy python test runner in [urfave/cli/pull/883](https://github.com/urfave/cli/pull/883) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n* Enable Go Modules support, drop support for `Go 1.10` add support for `Go 1.13` in [urfave/cli/pull/885](https://github.com/urfave/cli/pull/885) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n\n## [1.22.0] - 2019-09-07\n\n### Fixed\n\n* Fix Subcommands not falling back to `app.ExitEventHandler` in [urfave/cli/pull/856](https://github.com/urfave/cli/pull/856) via [@FaranIdo](https://github.com/FaranIdo)\n\n### Changed\n\n* Clarify that altsrc supports both TOML and JSON in [urfave/cli/pull/774](https://github.com/urfave/cli/pull/774) via [@whereswaldon](https://github.com/whereswaldon)\n* Made the exit code example more clear in [urfave/cli/pull/823](https://github.com/urfave/cli/pull/823) via [@xordspar0](https://github.com/xordspar0)\n* Removed the use of python for internal flag generation in [urfave/cli/pull/836](https://github.com/urfave/cli/pull/836) via [@asahasrabuddhe](https://github.com/asahasrabuddhe)\n* Changed the supported go versions to `1.10`, `1.11`, `1.12` in [urfave/cli/pull/843](https://github.com/urfave/cli/pull/843) via [@lafriks](https://github.com/lafriks)\n* Changed the v1 releases section in the readme in [urfave/cli/pull/862](https://github.com/urfave/cli/pull/862) via [@russoj88](https://github.com/russoj88)\n* Cleaned up go modules in [urfave/cli/pull/874](https://github.com/urfave/cli/pull/874) via [@saschagrunert](https://github.com/saschagrunert)\n\n### Added\n\n* Added `UseShortOptionHandling` for combining short flags in [urfave/cli/pull/735](https://github.com/urfave/cli/pull/735) via [@rliebz](https://github.com/rliebz)\n* Added support for flags bash completion in [urfave/cli/pull/808](https://github.com/urfave/cli/pull/808) via [@yogeshlonkar](https://github.com/yogeshlonkar)\n* Added the `TakesFile` indicator to flag in [urfave/cli/pull/851](https://github.com/urfave/cli/pull/851) via [@saschagrunert](https://github.com/saschagrunert)\n* Added fish shell completion support in [urfave/cli/pull/848](https://github.com/urfave/cli/pull/848) via [@saschagrunert](https://github.com/saschagrunert)\n\n## [1.21.0] - 2019-08-02\n\n### Fixed\n\n* Fix using \"slice\" flag types with `EnvVar` in [urfave/cli/pull/687](https://github.com/urfave/cli/pull/687) via [@joshuarubin](https://github.com/joshuarubin)\n* Fix regression of `SkipFlagParsing` behavior in [urfave/cli/pull/697](https://github.com/urfave/cli/pull/697) via [@jszwedko](https://github.com/jszwedko)\n* Fix handling `ShortOptions` and `SkipArgReorder` in [urfave/cli/pull/686](https://github.com/urfave/cli/pull/686) via [@baude](https://github.com/baude)\n* Fix args reordering when bool flags are present in [urfave/cli/pull/712](https://github.com/urfave/cli/pull/712) via [@windler](https://github.com/windler)\n* Fix parsing of short options in [urfave/cli/pull/758](https://github.com/urfave/cli/pull/758) via [@vrothberg](https://github.com/vrothberg)\n* Fix unaligned indents for the command help messages in [urfave/cli/pull/806](https://github.com/urfave/cli/pull/806) via [@mingrammer](https://github.com/mingrammer)\n\n### Changed\n\n* Cleaned up help output in [urfave/cli/pull/664](https://github.com/urfave/cli/pull/664) via [@maguro](https://github.com/maguro)\n* Remove redundant nil checks in [urfave/cli/pull/773](https://github.com/urfave/cli/pull/773) via [@teresy](https://github.com/teresy)\n* Case is now considered when sorting strings in [urfave/cli/pull/676](https://github.com/urfave/cli/pull/676) via [@rliebz](https://github.com/rliebz)\n\n### Added\n\n* Added _\"required flags\"_ support in [urfave/cli/pull/819](https://github.com/urfave/cli/pull/819) via [@lynncyrin](https://github.com/lynncyrin/)\n* Backport JSON `InputSource` to v1 in [urfave/cli/pull/598](https://github.com/urfave/cli/pull/598) via [@jszwedko](https://github.com/jszwedko)\n* Allow more customization of flag help strings in [urfave/cli/pull/661](https://github.com/urfave/cli/pull/661) via [@rliebz](https://github.com/rliebz)\n* Allow custom `ExitError` handler function in [urfave/cli/pull/628](https://github.com/urfave/cli/pull/628) via [@phinnaeus](https://github.com/phinnaeus)\n* Allow loading a variable from a file in [urfave/cli/pull/675](https://github.com/urfave/cli/pull/675) via [@jmccann](https://github.com/jmccann)\n* Allow combining short bool names in [urfave/cli/pull/684](https://github.com/urfave/cli/pull/684) via [@baude](https://github.com/baude)\n* Added test coverage to context in [urfave/cli/pull/788](https://github.com/urfave/cli/pull/788) via [@benzvan](https://github.com/benzvan)\n* Added go module support in [urfave/cli/pull/831](https://github.com/urfave/cli/pull/831) via [@saschagrunert](https://github.com/saschagrunert)\n\n## [1.20.0] - 2017-08-10\n\n### Fixed\n\n* `HandleExitCoder` is now correctly iterates over all errors in\n  a `MultiError`. The exit code is the exit code of the last error or `1` if\n  there are no `ExitCoder`s in the `MultiError`.\n* Fixed YAML file loading on Windows (previously would fail validate the file path)\n* Subcommand `Usage`, `Description`, `ArgsUsage`, `OnUsageError` correctly\n  propagated\n* `ErrWriter` is now passed downwards through command structure to avoid the\n  need to redefine it\n* Pass `Command` context into `OnUsageError` rather than parent context so that\n  all fields are available\n* Errors occurring in `Before` funcs are no longer double printed\n* Use `UsageText` in the help templates for commands and subcommands if\n  defined; otherwise build the usage as before (was previously ignoring this\n  field)\n* `IsSet` and `GlobalIsSet` now correctly return whether a flag is set if\n  a program calls `Set` or `GlobalSet` directly after flag parsing (would\n  previously only return `true` if the flag was set during parsing)\n\n### Changed\n\n* No longer exit the program on command/subcommand error if the error raised is\n  not an `OsExiter`. This exiting behavior was introduced in 1.19.0, but was\n  determined to be a regression in functionality. See [the\n  PR](https://github.com/urfave/cli/pull/595) for discussion.\n\n### Added\n\n* `CommandsByName` type was added to make it easy to sort `Command`s by name,\n  alphabetically\n* `altsrc` now handles loading of string and int arrays from TOML\n* Support for definition of custom help templates for `App` via\n  `CustomAppHelpTemplate`\n* Support for arbitrary key/value fields on `App` to be used with\n  `CustomAppHelpTemplate` via `ExtraInfo`\n* `HelpFlag`, `VersionFlag`, and `BashCompletionFlag` changed to explicitly be\n  `cli.Flag`s allowing for the use of custom flags satisfying the `cli.Flag`\n  interface to be used.\n\n\n## [1.19.1] - 2016-11-21\n\n### Fixed\n\n- Fixes regression introduced in 1.19.0 where using an `ActionFunc` as\n  the `Action` for a command would cause it to error rather than calling the\n  function. Should not have a affected declarative cases using `func(c\n  *cli.Context) err)`.\n- Shell completion now handles the case where the user specifies\n  `--generate-bash-completion` immediately after a flag that takes an argument.\n  Previously it call the application with `--generate-bash-completion` as the\n  flag value.\n\n## [1.19.0] - 2016-11-19\n### Added\n- `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`)\n- A `Description` field was added to `App` for a more detailed description of\n  the application (similar to the existing `Description` field on `Command`)\n- Flag type code generation via `go generate`\n- Write to stderr and exit 1 if action returns non-nil error\n- Added support for TOML to the `altsrc` loader\n- `SkipArgReorder` was added to allow users to skip the argument reordering.\n  This is useful if you want to consider all \"flags\" after an argument as\n  arguments rather than flags (the default behavior of the stdlib `flag`\n  library). This is backported functionality from the [removal of the flag\n  reordering](https://github.com/urfave/cli/pull/398) in the unreleased version\n  2\n- For formatted errors (those implementing `ErrorFormatter`), the errors will\n  be formatted during output. Compatible with `pkg/errors`.\n\n### Changed\n- Raise minimum tested/supported Go version to 1.2+\n\n### Fixed\n- Consider empty environment variables as set (previously environment variables\n  with the equivalent of `\"\"` would be skipped rather than their value used).\n- Return an error if the value in a given environment variable cannot be parsed\n  as the flag type. Previously these errors were silently swallowed.\n- Print full error when an invalid flag is specified (which includes the invalid flag)\n- `App.Writer` defaults to `stdout` when `nil`\n- If no action is specified on a command or app, the help is now printed instead of `panic`ing\n- `App.Metadata` is initialized automatically now (previously was `nil` unless initialized)\n- Correctly show help message if `-h` is provided to a subcommand\n- `context.(Global)IsSet` now respects environment variables. Previously it\n  would return `false` if a flag was specified in the environment rather than\n  as an argument\n- Removed deprecation warnings to STDERR to avoid them leaking to the end-user\n- `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This\n  fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well\n  as `altsrc` where Go would complain that the types didn't match\n\n## [1.18.1] - 2016-08-28\n### Fixed\n- Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported)\n\n## [1.18.0] - 2016-06-27\n### Added\n- `./runtests` test runner with coverage tracking by default\n- testing on OS X\n- testing on Windows\n- `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code\n\n### Changed\n- Use spaces for alignment in help/usage output instead of tabs, making the\n  output alignment consistent regardless of tab width\n\n### Fixed\n- Printing of command aliases in help text\n- Printing of visible flags for both struct and struct pointer flags\n- Display the `help` subcommand when using `CommandCategories`\n- No longer swallows `panic`s that occur within the `Action`s themselves when\n  detecting the signature of the `Action` field\n\n## [1.17.1] - 2016-08-28\n### Fixed\n- Removed deprecation warnings to STDERR to avoid them leaking to the end-user\n\n## [1.17.0] - 2016-05-09\n### Added\n- Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc`\n- `context.GlobalBoolT` was added as an analogue to `context.GlobalBool`\n- Support for hiding commands by setting `Hidden: true` -- this will hide the\n  commands in help output\n\n### Changed\n- `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer\n  quoted in help text output.\n- All flag types now include `(default: {value})` strings following usage when a\n  default value can be (reasonably) detected.\n- `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent\n  with non-slice flag types\n- Apps now exit with a code of 3 if an unknown subcommand is specified\n  (previously they printed \"No help topic for...\", but still exited 0. This\n  makes it easier to script around apps built using `cli` since they can trust\n  that a 0 exit code indicated a successful execution.\n- cleanups based on [Go Report Card\n  feedback](https://goreportcard.com/report/github.com/urfave/cli)\n\n## [1.16.1] - 2016-08-28\n### Fixed\n- Removed deprecation warnings to STDERR to avoid them leaking to the end-user\n\n## [1.16.0] - 2016-05-02\n### Added\n- `Hidden` field on all flag struct types to omit from generated help text\n\n### Changed\n- `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from\ngenerated help text via the `Hidden` field\n\n### Fixed\n- handling of error values in `HandleAction` and `HandleExitCoder`\n\n## [1.15.0] - 2016-04-30\n### Added\n- This file!\n- Support for placeholders in flag usage strings\n- `App.Metadata` map for arbitrary data/state management\n- `Set` and `GlobalSet` methods on `*cli.Context` for altering values after\nparsing.\n- Support for nested lookup of dot-delimited keys in structures loaded from\nYAML.\n\n### Changed\n- The `App.Action` and `Command.Action` now prefer a return signature of\n`func(*cli.Context) error`, as defined by `cli.ActionFunc`.  If a non-nil\n`error` is returned, there may be two outcomes:\n    - If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called\n    automatically\n    - Else the error is bubbled up and returned from `App.Run`\n- Specifying an `Action` with the legacy return signature of\n`func(*cli.Context)` will produce a deprecation message to stderr\n- Specifying an `Action` that is not a `func` type will produce a non-zero exit\nfrom `App.Run`\n- Specifying an `Action` func that has an invalid (input) signature will\nproduce a non-zero exit from `App.Run`\n\n### Deprecated\n- <a name=\"deprecated-cli-app-runandexitonerror\"></a>\n`cli.App.RunAndExitOnError`, which should now be done by returning an error\nthat fulfills `cli.ExitCoder` to `cli.App.Run`.\n- <a name=\"deprecated-cli-app-action-signature\"></a> the legacy signature for\n`cli.App.Action` of `func(*cli.Context)`, which should now have a return\nsignature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`.\n\n### Fixed\n- Added missing `*cli.Context.GlobalFloat64` method\n\n## [1.14.0] - 2016-04-03 (backfilled 2016-04-25)\n### Added\n- Codebeat badge\n- Support for categorization via `CategorizedHelp` and `Categories` on app.\n\n### Changed\n- Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`.\n\n### Fixed\n- Ensure version is not shown in help text when `HideVersion` set.\n\n## [1.13.0] - 2016-03-06 (backfilled 2016-04-25)\n### Added\n- YAML file input support.\n- `NArg` method on context.\n\n## [1.12.0] - 2016-02-17 (backfilled 2016-04-25)\n### Added\n- Custom usage error handling.\n- Custom text support in `USAGE` section of help output.\n- Improved help messages for empty strings.\n- AppVeyor CI configuration.\n\n### Changed\n- Removed `panic` from default help printer func.\n- De-duping and optimizations.\n\n### Fixed\n- Correctly handle `Before`/`After` at command level when no subcommands.\n- Case of literal `-` argument causing flag reordering.\n- Environment variable hints on Windows.\n- Docs updates.\n\n## [1.11.1] - 2015-12-21 (backfilled 2016-04-25)\n### Changed\n- Use `path.Base` in `Name` and `HelpName`\n- Export `GetName` on flag types.\n\n### Fixed\n- Flag parsing when skipping is enabled.\n- Test output cleanup.\n- Move completion check to account for empty input case.\n\n## [1.11.0] - 2015-11-15 (backfilled 2016-04-25)\n### Added\n- Destination scan support for flags.\n- Testing against `tip` in Travis CI config.\n\n### Changed\n- Go version in Travis CI config.\n\n### Fixed\n- Removed redundant tests.\n- Use correct example naming in tests.\n\n## [1.10.2] - 2015-10-29 (backfilled 2016-04-25)\n### Fixed\n- Remove unused var in bash completion.\n\n## [1.10.1] - 2015-10-21 (backfilled 2016-04-25)\n### Added\n- Coverage and reference logos in README.\n\n### Fixed\n- Use specified values in help and version parsing.\n- Only display app version and help message once.\n\n## [1.10.0] - 2015-10-06 (backfilled 2016-04-25)\n### Added\n- More tests for existing functionality.\n- `ArgsUsage` at app and command level for help text flexibility.\n\n### Fixed\n- Honor `HideHelp` and `HideVersion` in `App.Run`.\n- Remove juvenile word from README.\n\n## [1.9.0] - 2015-09-08 (backfilled 2016-04-25)\n### Added\n- `FullName` on command with accompanying help output update.\n- Set default `$PROG` in bash completion.\n\n### Changed\n- Docs formatting.\n\n### Fixed\n- Removed self-referential imports in tests.\n\n## [1.8.0] - 2015-06-30 (backfilled 2016-04-25)\n### Added\n- Support for `Copyright` at app level.\n- `Parent` func at context level to walk up context lineage.\n\n### Fixed\n- Global flag processing at top level.\n\n## [1.7.1] - 2015-06-11 (backfilled 2016-04-25)\n### Added\n- Aggregate errors from `Before`/`After` funcs.\n- Doc comments on flag structs.\n- Include non-global flags when checking version and help.\n- Travis CI config updates.\n\n### Fixed\n- Ensure slice type flags have non-nil values.\n- Collect global flags from the full command hierarchy.\n- Docs prose.\n\n## [1.7.0] - 2015-05-03 (backfilled 2016-04-25)\n### Changed\n- `HelpPrinter` signature includes output writer.\n\n### Fixed\n- Specify go 1.1+ in docs.\n- Set `Writer` when running command as app.\n\n## [1.6.0] - 2015-03-23 (backfilled 2016-04-25)\n### Added\n- Multiple author support.\n- `NumFlags` at context level.\n- `Aliases` at command level.\n\n### Deprecated\n- `ShortName` at command level.\n\n### Fixed\n- Subcommand help output.\n- Backward compatible support for deprecated `Author` and `Email` fields.\n- Docs regarding `Names`/`Aliases`.\n\n## [1.5.0] - 2015-02-20 (backfilled 2016-04-25)\n### Added\n- `After` hook func support at app and command level.\n\n### Fixed\n- Use parsed context when running command as subcommand.\n- Docs prose.\n\n## [1.4.1] - 2015-01-09 (backfilled 2016-04-25)\n### Added\n- Support for hiding `-h / --help` flags, but not `help` subcommand.\n- Stop flag parsing after `--`.\n\n### Fixed\n- Help text for generic flags to specify single value.\n- Use double quotes in output for defaults.\n- Use `ParseInt` instead of `ParseUint` for int environment var values.\n- Use `0` as base when parsing int environment var values.\n\n## [1.4.0] - 2014-12-12 (backfilled 2016-04-25)\n### Added\n- Support for environment variable lookup \"cascade\".\n- Support for `Stdout` on app for output redirection.\n\n### Fixed\n- Print command help instead of app help in `ShowCommandHelp`.\n\n## [1.3.1] - 2014-11-13 (backfilled 2016-04-25)\n### Added\n- Docs and example code updates.\n\n### Changed\n- Default `-v / --version` flag made optional.\n\n## [1.3.0] - 2014-08-10 (backfilled 2016-04-25)\n### Added\n- `FlagNames` at context level.\n- Exposed `VersionPrinter` var for more control over version output.\n- Zsh completion hook.\n- `AUTHOR` section in default app help template.\n- Contribution guidelines.\n- `DurationFlag` type.\n\n## [1.2.0] - 2014-08-02\n### Added\n- Support for environment variable defaults on flags plus tests.\n\n## [1.1.0] - 2014-07-15\n### Added\n- Bash completion.\n- Optional hiding of built-in help command.\n- Optional skipping of flag parsing at command level.\n- `Author`, `Email`, and `Compiled` metadata on app.\n- `Before` hook func support at app and command level.\n- `CommandNotFound` func support at app level.\n- Command reference available on context.\n- `GenericFlag` type.\n- `Float64Flag` type.\n- `BoolTFlag` type.\n- `IsSet` flag helper on context.\n- More flag lookup funcs at context level.\n- More tests &amp; docs.\n\n### Changed\n- Help template updates to account for presence/absence of flags.\n- Separated subcommand help template.\n- Exposed `HelpPrinter` var for more control over help output.\n\n## [1.0.0] - 2013-11-01\n### Added\n- `help` flag in default app flag set and each command flag set.\n- Custom handling of argument parsing errors.\n- Command lookup by name at app level.\n- `StringSliceFlag` type and supporting `StringSlice` type.\n- `IntSliceFlag` type and supporting `IntSlice` type.\n- Slice type flag lookups by name at context level.\n- Export of app and command help functions.\n- More tests &amp; docs.\n\n## 0.1.0 - 2013-07-22\n### Added\n- Initial implementation.\n\n[unreleased 2.X]: https://github.com/urfave/cli/compare/v2.2.0...HEAD\n[2.2.0]: https://github.com/urfave/cli/compare/v2.1.1...v2.2.0\n[2.1.1]: https://github.com/urfave/cli/compare/v2.1.0...v2.1.1\n[2.1.0]: https://github.com/urfave/cli/compare/v2.0.0...v2.1.0\n[2.0.0]: https://github.com/urfave/cli/compare/v1.22.2...v2.0.0\n\n[unreleased 1.22.X]: https://github.com/urfave/cli/compare/v1.22.4...v1\n[1.22.4]: https://github.com/urfave/cli/compare/v1.22.3...v1.22.4\n[1.22.3]: https://github.com/urfave/cli/compare/v1.22.2...v1.22.3\n[1.22.2]: https://github.com/urfave/cli/compare/v1.22.1...v1.22.2\n[1.22.1]: https://github.com/urfave/cli/compare/v1.22.0...v1.22.1\n[1.22.0]: https://github.com/urfave/cli/compare/v1.21.0...v1.22.0\n[1.21.0]: https://github.com/urfave/cli/compare/v1.20.0...v1.21.0\n[1.20.0]: https://github.com/urfave/cli/compare/v1.19.1...v1.20.0\n[1.19.1]: https://github.com/urfave/cli/compare/v1.19.0...v1.19.1\n[1.19.0]: https://github.com/urfave/cli/compare/v1.18.0...v1.19.0\n[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0\n[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0\n[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0\n[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0\n[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0\n[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0\n[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0\n[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1\n[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0\n[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2\n[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1\n[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0\n[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0\n[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0\n[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1\n[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0\n[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0\n[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0\n[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1\n[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0\n[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1\n[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0\n[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0\n[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0\n[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0\n"
  },
  {
    "path": "docs/CNAME",
    "content": "cli.urfave.org\n"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "content": "## Contributing\n\nWelcome to the `urfave/cli` contributor docs! This goal of this document is to help those\ninterested in joining the 200+ humans who have contributed to this project over the years.\n\n> As a general guiding principle, the current maintainers may be notified via the\n> @urfave/cli GitHub team.\n\nAll of the current maintainers are *volunteers* who live in various timezones with\ndifferent scheduling needs, so please understand that your contribution or question may\nnot get a response for many days.\n\n### semantic versioning adherence\n\nThe `urfave/cli` project strives to strictly adhere to [semantic\nversioning](https://semver.org/spec/v2.0.0.html). The active development branches and the\nmilestones and import paths to which they correspond are:\n\n#### `main` branch\n\n<https://github.com/urfave/cli/tree/main>\n\nThe majority of active development and issue management is targeting the `main` branch.\n\n- :arrow_right: [`v3.x`](https://github.com/urfave/cli/milestone/5)\n- :arrow_right: `github.com/urfave/cli/v3`\n\nThe `main` branch includes tooling to help with keeping track of `v3.x` series backward\ncompatibility. More details on this process are in the development workflow section below.\n\n#### `v1-maint` branch\n\n<https://github.com/urfave/cli/tree/v1-maint>\n\nThe `v1-maint` branch **MUST** only receive bug fixes in the `v1.22.x` series. There is no\nstrict rule regarding bug fixes to the `v3.x` or `v2.23.x` series being backported to the\n`v1.22.x` series.\n\n- :arrow_right: [`v1.22.x`](https://github.com/urfave/cli/milestone/11)\n- :arrow_right: `github.com/urfave/cli`\n\n#### `v2-maint` branch\n\n<https://github.com/urfave/cli/tree/v2-maint>\n\nThe `v2-maint` branch **MUST** only receive bug fixes in the `v2.23.x` series. There is no\nstrict rule regarding bug fixes to the `v3.x` series being backported to the `v2.23.x`\nseries.\n\n- :arrow_right: [`v2.23.x`](https://github.com/urfave/cli/milestone/16)\n- :arrow_right: `github.com/urfave/cli/v2`\n\n### development workflow\n\nMost of the tooling around the development workflow strives for effective\n[dogfooding](https://en.wikipedia.org/wiki/Eating_your_own_dog_food). There is a top-level\n`Makefile` that is maintained strictly for the purpose of easing verification of one's\ndevelopment environment and any changes one may have introduced:\n\n```sh\nmake\n```\n\nRunning the default `make` target (`all`) will ensure all of the critical steps are run to\nverify one's changes are harmonious in nature. The same steps are also run during the\n[continuous integration\nphase](https://github.com/urfave/cli/blob/main/.github/workflows/test.yml).\n\n`gfmrun` is required to run the examples, and without it `make all` will fail.\n\nYou can find `gfmrun` here:\n\n- [urfave/gfmrun](https://github.com/urfave/gfmrun)\n\nTo install `gfmrun`, you can use `go install`:\n\n```\ngo install github.com/urfave/gfmrun/cmd/gfmrun@latest\n```\n\nIn the event that the `v3diff` target exits non-zero, this is a signal that the public API\nsurface area has changed. If the changes are acceptable, then manually running the\napproval step will \"promote\" the current `go doc` output:\n\n```sh\nmake v3approve\n```\n\nBecause the `generate` step includes updating `godoc-current.txt` and\n`testdata/godoc-v3.x.txt`, these changes *MUST* be part of any proposed pull request so\nthat reviewers have an opportunity to also make an informed decision about the \"promotion\"\nstep.\n\n#### docs output\n\nThe documentation in the `docs` directory is automatically built via `mkdocs` into a\nstatic site and published when releases are pushed (see [RELEASING](./RELEASING.md)). There\nis no strict requirement to build the documentation when developing locally, but the\nfollowing `make` targets may be used if desired:\n\n```sh\n# install documentation dependencies with `pip`\nmake ensure-mkdocs\n```\n\n```sh\n# build the static site in `./site`\nmake docs\n```\n\n```sh\n# start an mkdocs development server\nmake serve-docs\n```\n\n### pull requests\n\nPlease feel free to open a pull request to fix a bug or add a feature. The @urfave/cli\nteam will review it as soon as possible, giving special attention to maintaining backward\ncompatibility. If the @urfave/cli team agrees that your contribution is in line with the\nvision of the project, they will work with you to get the code into a mergeable state,\nmerged, and then released.\n\n### granting of commit bit / admin mode\n\nThose with a history of contributing to this project will likely be invited to join the\n@urfave/cli team. As a member of the @urfave/cli team, you will have the ability to fully\nadminister pull requests, issues, and other repository bits.\n\nIf you feel that you should be a member of the @urfave/cli team but have not yet been\nadded, the most likely explanation is that this is an accidental oversight! :sweat_smile:.\nPlease open an issue!\n\n<!--\nvim:tw=90\n-->\n"
  },
  {
    "path": "docs/RELEASING.md",
    "content": "# Releasing urfave/cli\n\nReleasing small batches often is [backed by\nresearch](https://itrevolution.com/accelerate-book/) as part of the\nvirtuous cycles that keep teams and products healthy.\n\nTo that end, the overall goal of the release process is to send\nchanges out into the world as close to the time the commits were\nmerged to the `main` branch as possible. In this way, the community\nof humans depending on this library are able to make use of the\nchanges they need **quickly**, which means they shouldn't have to\nmaintain long-lived forks of the project, which means they can get\nback to focusing on the work on which they want to focus. This also\nmeans that the @urfave/cli team should be able to focus on\ndelivering a steadily improving product with significantly eased\nability to associate bugs and regressions with specific releases.\n\n## Process\n\n- Release versions follow [semantic versioning](https://semver.org/)\n- Releases are associated with **signed, annotated git tags**[^1].\n- Release notes are **automatically generated**[^2].\n\nIn the `main` or `v2-maint` branch, the current version is always\navailable via:\n\n```sh\ngit describe --always --dirty --tags\n```\n\n**NOTE**: if the version reported contains `-dirty`, this is\nindicative of a \"dirty\" work tree, which is not a great state for\ncreating a new release tag. Seek help from @urfave/cli teammates.\n\nFor example, given a described version of `v2.4.7-3-g68da1cd` and a\ndiff of `v2.4.7...` that contains only bug fixes, the next version\nshould be `v2.4.8`:\n\n```sh\ngit tag -a -s -m 'Release 2.4.8' v2.4.8\ngit push origin v2.4.8\n```\n\nThe tag push will trigger a GitHub Actions workflow and will be\n**immediately available** to the [Go module mirror, index, and\nchecksum database](https://proxy.golang.org/). The remaining steps\nrequire human intervention through the GitHub web view although\n[automated solutions\nexist](https://github.com/softprops/action-gh-release) that may be\nadopted in the future.\n\n- Open the [the new release page](https://github.com/urfave/cli/releases/new)\n- At the top of the form, click on the `Choose a tag` select control and select `v2.4.8`\n- In the `Write` tab below, click the `Auto-generate release notes` button\n- At the bottom of the form, click the `Publish release` button\n- :white_check_mark: you're done!\n\n[^1]: This was not always true. There are many **lightweight git\n  tags** present in the repository history.\n\n[^2]: This was not always true. The\n  [`docs/CHANGELOG.md`](./CHANGELOG.md) document used to be\n  manually maintained. Relying on the automatic release notes\n  generation requires the use of **merge commits** as opposed to\n  squash merging or rebase merging.\n"
  },
  {
    "path": "docs/SECURITY.md",
    "content": "# Security Policy\n\nHello and thank you for your interest in the `urfave/cli` security\npolicy! :tada: :lock:\n\n## Supported Versions\n\n| Version      | Supported                             |\n| ------------ | ------------------------------------- |\n| `>= v2.3.x`  | :white_check_mark:                    |\n| `< v2.3`     | :x:                                   |\n| `>= v1.22.x` | :white_check_mark: :lady_beetle: [^1] |\n| `< v1.22`    | :x:                                   |\n\n## Reporting a Vulnerability\n\nPlease disclose any vulnerabilities by sending an email to:\n\n[urfave-security@googlegroups.com](mailto:urfave-security@googlegroups.com)\n\nYou should expect a response within 48 hours and further\ncommunications to be decided via email. The `urfave/cli` maintainer\nteam comprises volunteers who contribute when possible, so please\nhave patience :bow:\n\n[^1]: The `v1.22.x` series will receive bug fixes and security\n  patches only.\n"
  },
  {
    "path": "docs/go.mod",
    "content": "module github.com/urfave/cli/docs/v3\n\ngo 1.23.2\n\nreplace github.com/urfave/cli/v3 => ../\n\nrequire (\n\tgithub.com/urfave/cli-altsrc/v3 v3.0.1\n\tgithub.com/urfave/cli/v3 v3.1.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/stretchr/testify v1.11.1 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "docs/go.sum",
    "content": "github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=\ngithub.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/urfave/cli-altsrc/v3 v3.0.0-alpha2 h1:j4SaBpPB8++L0c0KuTnz/Yus3UQoWJ54hQjhIMW8rCM=\ngithub.com/urfave/cli-altsrc/v3 v3.0.0-alpha2/go.mod h1:Q79oyIY/z4jtzIrKEK6MUeWC7/szGr46x4QdOaOAIWc=\ngithub.com/urfave/cli-altsrc/v3 v3.0.1 h1:v+gHk59syLk8ao9rYybZs43+D5ut/gzj0omqQ1XYl8k=\ngithub.com/urfave/cli-altsrc/v3 v3.0.1/go.mod h1:8UtsKKcxFVzvaoySFPfvQOk413T+IXJhaCWyyoPW3yM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "docs/index.md",
    "content": "<!--\nNOTE: This first section is intentionally identical to the top-level README.md at\nhttps://github.com/urfave/cli/blob/main/README.md\n-->\n# Welcome to urfave/cli\n\n[![Run Tests](https://github.com/urfave/cli/actions/workflows/test.yml/badge.svg)](https://github.com/urfave/cli/actions/workflows/test.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/urfave/cli/v3.svg)](https://pkg.go.dev/github.com/urfave/cli/v3)\n[![Go Report Card](https://goreportcard.com/badge/github.com/urfave/cli/v3)](https://goreportcard.com/report/github.com/urfave/cli/v3)\n[![codecov](https://codecov.io/gh/urfave/cli/branch/main/graph/badge.svg?token=t9YGWLh05g)](https://codecov.io/gh/urfave/cli)\n\nurfave/cli is a **declarative**, simple, fast, and fun package for building command line tools in Go featuring:\n\n- commands and subcommands with alias and prefix match support\n- flexible and permissive help system\n- dynamic shell completion for `bash`, `zsh`, `fish`, and `powershell`\n- `man` and markdown format documentation generation\n- input flags for simple types, slices of simple types, time, duration, and others\n- compound short flag support (`-a` `-b` `-c` :arrow_right: `-abc`)\n- input lookup from:\n    - environment variables\n    - plain text files\n    - [structured file formats supported via the `urfave/cli-altsrc` package](https://github.com/urfave/cli-altsrc)\n\n<!--\n/END first section that is identical to README.md first section\n-->\n\nThese are the guides for each major version:\n\n- [`v3`](./v3/getting-started.md)\n- [`v2`](./v2/getting-started.md)\n- [`v1`](./v1/getting-started.md)\n\nIn addition to the version-specific guides, these other documents are available:\n\n- [CONTRIBUTING](./CONTRIBUTING.md)\n- [CODE OF CONDUCT](./CODE_OF_CONDUCT.md)\n- [RELEASING](./RELEASING.md)\n\n## Installation\n\nUsing this package requires a working Go environment. [See the install instructions for Go](https://go.dev/doc/install).\n\nGo Modules are required when using this package. [See the go blog guide on using Go Modules](https://blog.golang.org/using-go-modules).\n\n### Using `v3` releases\n\nThe latest `v3` release may be installed via the `/v3` suffix and is the\nrecommended version for all new development. The state of the [`main`\nbranch](https://github.com/urfave/cli/tree/main) at any given time **may**\ncorrespond to a `v3` series release or pre-release.  Please see the [`v3`\nmigration guide](./migrate-v2-to-v3.md) on using v3 if you are upgrading from\nv2.\n\n```sh\ngo get github.com/urfave/cli/v3@latest\n```\n\n```go\nimport (\n  \"github.com/urfave/cli/v3\" // imports as package \"cli\"\n)\n```\n\n### Using `v2` releases\n\n:warning: The `v2` series is receiving **security and bug fixes only** via the\n[`v2-maint` branch](https://github.com/urfave/cli/tree/v2-maint) and **should\nnot** be used in new development. Please see the [`v3` migration\nguide](./migrate-v2-to-v3.md) and feel free to open an issue or discussion if\nyou need help with the migration to `v3`.\n\n```sh\ngo get github.com/urfave/cli/v2@latest\n```\n\n```go\nimport (\n  \"github.com/urfave/cli/v2\" // imports as package \"cli\"\n)\n```\n\n### Using `v1` releases\n\n:warning: The `v1` series is receiving **security fixes only** via the\n[`v1-maint` branch](https://github.com/urfave/cli/tree/v1-maint) and **should\nnot** be used in new development. Please see the [`v2` migration\nguide](./migrate-v1-to-v2.md) and feel free to open an issue or discussion if\nyou need help with the migration to `v2`.\n\n### Supported platforms\n\ncli is tested against multiple versions of Go on Linux, and against the latest\nreleased version of Go on OS X and Windows. This project uses GitHub Actions\nfor builds. To see our currently supported go versions and platforms, look at\nthe [github workflow\nconfiguration](https://github.com/urfave/cli/blob/main/.github/workflows/test.yml).\n"
  },
  {
    "path": "docs/migrate-v1-to-v2.md",
    "content": "# Migration Guide: v1 to v2\n\nv2 has a number of breaking changes but converting is relatively\nstraightforward: make the changes documented below then resolve any\ncompiler errors. We hope this will be sufficient for most typical\nusers.\n\nIf you find any issues not covered by this document, please post a\ncomment on [Issue 921](https://github.com/urfave/cli/issues/921) or\nconsider sending a PR to help improve this guide.\n\n## Flags before args\n\nIn v2 flags must come before args. This is more POSIX-compliant.  You\nmay need to update scripts, user documentation, etc.\n\nThis will work:\n\n```\ncli hello --shout rick\n```\n\nThis will not:\n\n```\ncli hello rick --shout\n```\n\n## Import string changed\n\n=== \"v1\"\n\n    `import \"github.com/urfave/cli\"`\n\n=== \"v2\"\n\n    `import \"github.com/urfave/cli/v2\"`\n\nCheck each file for this and make the change.\n\nShell command to find them all: `fgrep -rl github.com/urfave/cli *`\n\n## Flag aliases are done differently\n\nChange `Name: \"foo, f\"` to `Name: \"foo\", Aliases: []string{\"f\"}`\n\n=== \"v1\"\n\n    ```go\n    cli.StringFlag{\n            Name: \"config, cfg\"\n    }\n    ```\n\n=== \"v2\"\n    \n    ```go\n    cli.StringFlag{\n            Name: \"config\",\n            Aliases: []string{\"cfg\"},\n    }\n    ```\n\nSadly v2 doesn't warn you if a comma is in the name.\n(https://github.com/urfave/cli/issues/1103)\n\n## EnvVar is now a list (EnvVars)\n\nChange `EnvVar: \"XXXXX\"` to `EnvVars: []string{\"XXXXX\"}` (plural).\n\n=== \"v1\"\n\n    ```go\n    cli.StringFlag{\n            EnvVar: \"APP_LANG\"\n    }\n    ```\n\n=== \"v2\"\n\n    ```go\n    cli.StringFlag{\n            EnvVars: []string{\"APP_LANG\"}\n    }\n    ```\n\n## Actions returns errors\n\nA command's `Action:` now returns an `error`.\n\n=== \"v1\"\n\n    `Action: func(c *cli.Context) {`\n\n=== \"v2\"\n\n    `Action: func(c *cli.Context) error {`\n\nCompiler messages you might see:\n\n```\ncannot use func literal (type func(*cli.Context)) as type cli.ActionFunc in field value\n```\n\n## cli.Flag changed\n\n`cli.Flag` is now a list of pointers.\n\nWhat this means to you:\n\nIf you make a list of flags, add a `&` in front of each\nitem.   cli.BoolFlag, cli.StringFlag, etc.\n\n=== \"v1\"\n\n    ```go\n            app.Flags = []cli.Flag{\n                   cli.BoolFlag{\n    ```\n\n=== \"v2\"\n    \n    ```go\n            app.Flags = []cli.Flag{\n                   &cli.BoolFlag{\n    ```\n\nCompiler messages you might see:\n\n```\n\tcli.StringFlag does not implement cli.Flag (Apply method has pointer receiver)\n```\n\n## Commands are now lists of pointers\n\nOccurrences of `[]Command` have been changed to `[]*Command`.\n\nWhat this means to you:\n\nLook for `[]cli.Command{}` and change it to `[]*cli.Command{}`\n\nExample:\n\n=== \"v1\"\n\n    `var commands = []cli.Command{}`\n\n=== \"v2\"\n\n    `var commands = []*cli.Command{}`\n\nCompiler messages you might see:\n\n```\ncannot convert commands (type []cli.Command) to type cli.CommandsByName\ncannot use commands (type []cli.Command) as type []*cli.Command in assignment\n```\n\n## Lists of commands should be pointers\n\nIf you are building up a list of commands, the individual items should\nnow be pointers.\n\n=== \"v1\"\n\n    `cli.Command{`\n\n=== \"v2\"\n\n    `&cli.Command{`\n\nCompiler messages you might see:\n\n```\ncannot use cli.Command literal (type cli.Command) as type *cli.Command in argument to\n```\n\n## Appending Commands\n\nAppending to a list of commands needs to be changed since the list is\nnow pointers.\n\n=== \"v1\"\n\n    `commands = append(commands, *c)`\n\n=== \"v2\"\n\n    `commands = append(commands, c)`\n\nCompiler messages you might see:\n\n```\ncannot use c (type *cli.Command) as type cli.Command in append\n```\n\n## GlobalString, GlobalBool and its likes are deprecated\n\nUse simply `String` instead of `GlobalString`, `Bool` instead of `GlobalBool` \n\n## BoolTFlag and BoolT are deprecated\n\nBoolTFlag was a Bool Flag with its default value set to true and BoolT was used to find any BoolTFlag used locally, so both are deprecated.\n\n=== \"v1\"\n\n    ```go\n    cli.BoolTFlag{\n            Name:   FlagName,\n            Usage:  FlagUsage,\n            EnvVar: \"FLAG_ENV_VAR\",\n    }\n    ```\n\n=== \"v2\"\n    \n    ```go\n    cli.BoolFlag{\n            Name:   FlagName,\n            Value:  true,\n            Usage:  FlagUsage,\n            EnvVar: \"FLAG_ENV_VAR\",\n    }\n    ```\n\n## &cli.StringSlice{\"\"} replaced with cli.NewStringSlice(\"\")\n\nExample: \n\n=== \"v1\"\n\n    ```go\n    Value: &cli.StringSlice{\"\"},\n    ```\n\n=== \"v2\"\n    \n    ```go\n    Value: cli.NewStringSlice(\"\"),\n    ```\n\n## Replace deprecated functions\n\n`cli.NewExitError()` is deprecated.  Use `cli.Exit()` instead.  ([Staticcheck](https://staticcheck.io/) detects this automatically and recommends replacement code.)\n\n## Everything else\n\nCompile the code and work through any errors. Most should\nrelate to issues listed above.\n\nOnce it compiles, test the command. Review the output of `-h` or any\nhelp messages to verify they match the intended flags and subcommands.\nThen test the program itself.\n\nIf you find any issues not covered by this document please let us know\nby submitting a comment on\n[Issue 921](https://github.com/urfave/cli/issues/921)\nso that others can benefit.\n"
  },
  {
    "path": "docs/migrate-v2-to-v3.md",
    "content": "# Migration Guide: v2 to v3\n\nv3 has a number of breaking changes but converting is relatively\nstraightforward: make the changes documented below then resolve any\ncompiler errors. We hope this will be sufficient for most typical\nusers.\n\nIf you find any issues not covered by this document, please post a\ncomment on [the discussion](https://github.com/urfave/cli/discussions/2084) or\nconsider sending a PR to help improve this guide.\n\n## New Import\n\n=== \"v2\"\n\n    `import \"github.com/urfave/cli/v2\"`\n\n=== \"v3\"\n\n    `import \"github.com/urfave/cli/v3\"`\n\nCheck each file for this and make the change.\n\nShell command to find them all: `fgrep -rl github.com/urfave/cli/v2 *`\n\n## New Names\n\n### cli.App\n\n=== \"v2\"\n\n    ```go\n    cli.App{\n            // ...\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.Command{\n            // ...\n    }\n    ```\n\n### cli.App.EnableBashCompletion\n\n=== \"v2\"\n\n    ```go\n    cli.App{\n            EnableBashCompletion: true,\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.Command{\n            EnableShellCompletion: true,\n    }\n    ```\n\n### cli.App.CustomAppHelpTemplate\n\n=== \"v2\"\n\n    ```go\n    cli.App{\n            CustomAppHelpTemplate: \"...\",\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.Command{\n            CustomRootCommandHelpTemplate: \"...\",\n    }\n    ```\n\n### cli.App.RunContext\n\n=== \"v2\"\n\n    ```go\n    (&cli.App{}).RunContext(context.Background(), os.Args)\n    ```\n\n=== \"v3\"\n\n    ```go\n    (&cli.Command{}).Run(context.Background(), os.Args)\n    ```\n\n### cli.App.BashComplete\n\n=== \"v2\"\n\n    ```go\n    cli.App{\n            BashComplete: func(ctx *cli.Context) {},\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.Command{\n            ShellComplete: func(ctx context.Context, cmd *cli.Command) {},\n    }\n    ```\n\n### cli.Command.Subcommands\n\n=== \"v2\"\n\n    ```go\n    cli.Command{\n            Subcommands: []*cli.Command{},\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.Command{\n            Commands: []*cli.Command{},\n    }\n    ```\n\n## Sources\n\n### FilePath\n\n=== \"v2\"\n\n    ```go\n    cli.StringFlag{\n            FilePath: \"/path/to/foo\",\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.StringFlag{\n            Sources: cli.Files(\"/path/to/foo\"),\n    }\n    ```\n\n    or \n\n    ```go\n    cli.StringFlag{\n        Sources: cli.NewValueSourceChain(\n            cli.File(\"/path/to/foo\"),\n        ),\n    }\n    ```\n\n### EnvVars\n\n=== \"v2\"\n\n    ```go\n    cli.StringFlag{\n            EnvVars: []string{\"APP_LANG\"},\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    cli.StringFlag{\n            Sources: cli.EnvVars(\"APP_LANG\"),\n    }\n    ```\n\n    or \n\n    ```go\n    cli.StringFlag{\n        Sources: cli.NewValueSourceChain(\n           cli.EnvVar(\"APP_LANG\"),\n        ),\n    }\n    ```\n\n### Altsrc\n\n#### Altsrc is now a dedicated module\n\n=== \"v2\"\n\n    `import \"github.com/urfave/cli/v2/altsrc\"`\n\n=== \"v3\"\n\n    `import altsrc \"github.com/urfave/cli-altsrc/v3\"`\n\n#### Altsrc is now a value source for CLI\n\n=== \"v2\"\n    \n    ```go\n    altsrc.NewStringFlag(\n        &cli.StringFlag{\n            Name:        \"key\",\n            Value:       \"/tmp/foo\",\n        },\n    ),\n    ```\n\n=== \"v3\"\n    \n    Requires to use at least `github.com/urfave/cli-altsrc/v3@v3.0.0-alpha2.0.20250227140532-11fbec4d81a7`\n\n    ```go\n    cli.StringFlag{\n        Sources: cli.NewValueSourceChain(altsrcjson.JSON(\"key\", altsrc.StringSourcer(\"/path/to/foo.json\"))),\n    }\n    ```\n\n### Order of precedence of envvars, filepaths, altsrc now depends on the order in which they are defined\n\n=== \"v2\"\n\n    ```go\n    altsrc.NewStringFlag(\n        &cli.StringFlag{\n            Name:     \"key\",\n            EnvVars:  []string{\"APP_LANG\"},\n            FilePath: \"/path/to/foo\",\n        },\n    ),\n    ```\n\n=== \"v3\"\n\n    Requires to use at least `github.com/urfave/cli-altsrc/v3@v3.0.0-alpha2.0.20250227140532-11fbec4d81a7` \n\n    ```go\n    import altsrcjson \"github.com/urfave/cli-altsrc/v3/json\"\n    \n    // ...\n\n    &cli.StringFlag{\n        Name: \"key\",\n        Sources: cli.NewValueSourceChain(\n            cli.EnvVar(\"APP_LANG\"),\n            cli.File(\"/path/to/foo\"),\n            altsrcjson.JSON(\"key\", altsrc.StringSourcer(\"/path/to/foo.json\")),\n        ),\n    },\n    ```\n\nIn the above case the Envs are checked first and if not found then files are looked at and then finally the `altsrc`\n\n## cli.Context has been removed\n\nAll functions handled previously by `cli.Context` have been incorporated into `cli.Command`:\n\n| v2                           | v3                           |\n|------------------------------|------------------------------|\n| `cli.Context.IsSet`          | `cli.Command.IsSet`          |\n| `cli.Context.NumFlags`       | `cli.Command.NumFlags`       |\n| `cli.Context.FlagNames`      | `cli.Command.FlagNames`      |\n| `cli.Context.LocalFlagNames` | `cli.Command.LocalFlagNames` |\n| `cli.Context.Lineage`        | `cli.Command.Lineage`        |\n| `cli.Context.Count`          | `cli.Command.Count`          |\n| `cli.Context.Value`          | `cli.Command.Value`          |\n| `cli.Context.Args`           | `cli.Command.Args`           |\n| `cli.Context.NArg`           | `cli.Command.NArg`           |\n\n## Handler Function Signatures Changes\n\nAll handler functions now take at least 2 arguments a `context.Context` and a pointer to `Cli.Command`\nin addition to other specific args. This allows handler functions to utilize `context.Context` for\nblocking/time-specific operations and so on.\n\n### BeforeFunc\n\n=== \"v2\"\n\n    `type BeforeFunc func(*Context) error`\n\n=== \"v3\"\n\n    `type BeforeFunc func(context.Context, *cli.Command) (context.Context, error)`\n\n### AfterFunc\n\n=== \"v2\"\n\n    `type AfterFunc func(*Context) error`\n\n=== \"v3\"\n\n    `type AfterFunc func(context.Context, *cli.Command) error`\n\n### ActionFunc\n\n=== \"v2\"\n\n    `type ActionFunc func(*Context) error`\n\n=== \"v3\"\n\n    `type ActionFunc func(context.Context, *cli.Command) error`\n\n### CommandNotFoundFunc\n\n=== \"v2\"\n\n    `type CommandNotFoundFunc func(*Context, string) error`\n\n=== \"v3\"\n\n    `type CommandNotFoundFunc func(context.Context, *cli.Command, string) error`\n\n### OnUsageErrorFunc\n\n=== \"v2\"\n\n    `type OnUsageErrorFunc func(*Context, err error, isSubcommand bool) error`\n\n=== \"v3\"\n\n    `type OnUsageErrorFunc func(context.Context, *cli.Command, err error, isSubcommand bool) error`\n\n### InvalidAccessFunc\n\n=== \"v2\"\n\n    `type InvalidAccessFunc func(*Context, string) error`\n\n=== \"v3\"\n\n    `type InvalidAccessFunc func(context.Context, *cli.Command, string) error`\n\n### ExitErrHandlerFunc\n\n=== \"v2\"\n\n    `type ExitErrHandlerFunc func(*Context, err error) error`\n\n=== \"v3\"\n\n    `type ExitErrHandlerFunc func(context.Context, *cli.Command, err error) error`\n\nCompiler messages you might see(for ActionFunc):\n\n```\ncannot use func literal (type func(*cli.Context) error) as type cli.ActionFunc in field value\n```\n\nSimilar messages would be shown for other funcs.\n\n## TimestampFlag\n\n=== \"v2\"\n\n    ```go\n    &cli.TimestampFlag{\n        Name:   \"foo\",\n        Layout: time.RFC3339,\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    &cli.TimestampFlag{\n        Name:  \"foo\",\n        Config: cli.TimestampConfig{\n            Layouts: []string{time.RFC3339},\n        },\n    }\n    ```\n\n## PathFlag\n\n=== \"v2\"\n\n    ```go\n    &cli.PathFlag{\n        Name:   \"foo\",\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    &cli.StringFlag{\n        Name:  \"foo\",\n        TakesFile: true,\n    }\n    ```\n\n## Authors\n\n=== \"v2\"\n\n    ```go\n    &cli.App{\n        Authors: []*cli.Author{\n            {Name: \"Some Guy\", Email: \"someguy@example.com\"},\n        },\n    }\n    ```\n\n=== \"v3\"\n\n    ```go\n    // import \"net/mail\"\n    &cli.Command{\n        Authors: []any{\n            mail.Address{Name: \"Some Guy\", Address: \"someguy@example.com\"},\n        },\n    }\n    ```\n"
  },
  {
    "path": "docs/package.go",
    "content": "// Package docs is an empty shell! This file is *only* meant to capture the dependencies\n// required by the `gfmrun` documentation tests.\n\npackage docs\n\nimport (\n\t_ \"github.com/urfave/cli-altsrc/v3\"\n\t_ \"github.com/urfave/cli/v3\"\n)\n"
  },
  {
    "path": "docs/v1/examples/arguments.md",
    "content": "---\ntags:\n  - v1\n---\n\nYou can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:\n\n<!-- {\n  \"output\": \"Hello \\\"\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Action = func(c *cli.Context) error {\n    fmt.Printf(\"Hello %q\", c.Args().Get(0))\n    return nil\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n"
  },
  {
    "path": "docs/v1/examples/bash-completions.md",
    "content": "---\ntags:\n  - v1\n---\n\nYou can enable completion commands by setting the `EnableBashCompletion`\nflag on the `App` object.  By default, this setting will only auto-complete to\nshow an app's subcommands, but you can write your own completion methods for\nthe App or its subcommands.\n\n<!-- {\n  \"args\": [\"complete\", \"&#45;&#45;generate&#45;bash&#45;completion\"],\n  \"output\": \"laundry\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  tasks := []string{\"cook\", \"clean\", \"laundry\", \"eat\", \"sleep\", \"code\"}\n\n  app := cli.NewApp()\n  app.EnableBashCompletion = true\n  app.Commands = []cli.Command{\n    {\n      Name:  \"complete\",\n      Aliases: []string{\"c\"},\n      Usage: \"complete a task on the list\",\n      Action: func(c *cli.Context) error {\n         fmt.Println(\"completed task: \", c.Args().First())\n         return nil\n      },\n      BashComplete: func(c *cli.Context) {\n        // This will complete if no args are passed\n        if c.NArg() > 0 {\n          return\n        }\n        for _, t := range tasks {\n          fmt.Println(t)\n        }\n      },\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\n#### Enabling\n\nSource the `autocomplete/bash_autocomplete` file in your `.bashrc` file while\nsetting the `PROG` variable to the name of your program:\n\n`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`\n\n#### Distribution\n\nCopy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename\nit to the name of the program you wish to add autocomplete support for (or\nautomatically install it there if you are distributing a package). Don't forget\nto source the file to make it active in the current shell.\n\n```\nsudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>\nsource /etc/bash_completion.d/<myprogram>\n```\n\nAlternatively, you can just document that users should source the generic\n`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set\nto the name of their program (as above).\n\n#### Customization\n\nThe default bash completion flag (`--generate-bash-completion`) is defined as\n`cli.BashCompletionFlag`, and may be redefined if desired, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45;compgen\"],\n  \"output\": \"wat\\nhelp\\nh\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  cli.BashCompletionFlag = cli.BoolFlag{\n    Name:   \"compgen\",\n    Hidden: true,\n  }\n\n  app := cli.NewApp()\n  app.EnableBashCompletion = true\n  app.Commands = []cli.Command{\n    {\n      Name: \"wat\",\n    },\n  }\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n"
  },
  {
    "path": "docs/v1/examples/combining-short-options.md",
    "content": "---\ntags:\n  - v1\n---\n\nTraditional use of options using their shortnames look like this:\n\n```\n$ cmd -s -o -m \"Some message\"\n```\n\nSuppose you want users to be able to combine options with their shortnames. This\ncan be done using the `UseShortOptionHandling` bool in your app configuration,\nor for individual commands by attaching it to the command configuration. For\nexample:\n\n<!-- {\n  \"args\": [\"short\", \"&#45;som\", \"Some message\"],\n  \"output\": \"serve: true\\noption: true\\nmessage: Some message\\n\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n  app.UseShortOptionHandling = true\n  app.Commands = []cli.Command{\n    {\n      Name:  \"short\",\n      Usage: \"complete a task on the list\",\n      Flags: []cli.Flag{\n        cli.BoolFlag{Name: \"serve, s\"},\n        cli.BoolFlag{Name: \"option, o\"},\n        cli.StringFlag{Name: \"message, m\"},\n      },\n      Action: func(c *cli.Context) error {\n        fmt.Println(\"serve:\", c.Bool(\"serve\"))\n        fmt.Println(\"option:\", c.Bool(\"option\"))\n        fmt.Println(\"message:\", c.String(\"message\"))\n        return nil\n      },\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nIf your program has any number of bool flags such as `serve` and `option`, and\noptionally one non-bool flag `message`, with the short options of `-s`, `-o`,\nand `-m` respectively, setting `UseShortOptionHandling` will also support the\nfollowing syntax:\n\n```\n$ cmd -som \"Some message\"\n```\n\nIf you enable `UseShortOptionHandling`, then you must not use any flags that\nhave a single leading `-` or this will result in failures. For example,\n`-option` can no longer be used. Flags with two leading dashes (such as\n`--options`) are still valid.\n"
  },
  {
    "path": "docs/v1/examples/exit-codes.md",
    "content": "---\ntags:\n  - v1\n---\n\nCalling `App.Run` will not automatically call `os.Exit`, which means that by\ndefault the exit code will \"fall through\" to being `0`.  An explicit exit code\nmay be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a\n`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:\n<!-- {\n  \"error\": \"Ginger croutons are not in the soup\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n  app.Flags = []cli.Flag{\n    cli.BoolFlag{\n      Name:  \"ginger-crouton\",\n      Usage: \"Add ginger croutons to the soup\",\n    },\n  }\n  app.Action = func(ctx *cli.Context) error {\n    if !ctx.Bool(\"ginger-crouton\") {\n      return cli.NewExitError(\"Ginger croutons are not in the soup\", 86)\n    }\n    return nil\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n"
  },
  {
    "path": "docs/v1/examples/flags.md",
    "content": "---\ntags:\n  - v1\n---\n\nSetting and querying flags is simple.\n\n<!-- {\n  \"output\": \"Hello Nefertiti\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name: \"lang\",\n      Value: \"english\",\n      Usage: \"language for the greeting\",\n    },\n  }\n\n  app.Action = func(c *cli.Context) error {\n    name := \"Nefertiti\"\n    if c.NArg() > 0 {\n      name = c.Args().Get(0)\n    }\n    if c.String(\"lang\") == \"spanish\" {\n      fmt.Println(\"Hola\", name)\n    } else {\n      fmt.Println(\"Hello\", name)\n    }\n    return nil\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nYou can also set a destination variable for a flag, to which the content will be\nscanned.\n\n<!-- {\n  \"output\": \"Hello someone\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n  \"fmt\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  var language string\n\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name:        \"lang\",\n      Value:       \"english\",\n      Usage:       \"language for the greeting\",\n      Destination: &language,\n    },\n  }\n\n  app.Action = func(c *cli.Context) error {\n    name := \"someone\"\n    if c.NArg() > 0 {\n      name = c.Args()[0]\n    }\n    if language == \"spanish\" {\n      fmt.Println(\"Hola\", name)\n    } else {\n      fmt.Println(\"Hello\", name)\n    }\n    return nil\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nSee full list of flags at https://pkg.go.dev/github.com/urfave/cli\n\n#### Placeholder Values\n\nSometimes it's useful to specify a flag's value within the usage string itself.\nSuch placeholders are indicated with back quotes.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;config FILE, &#45;c FILE\"\n} -->\n```go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag{\n    cli.StringFlag{\n      Name:  \"config, c\",\n      Usage: \"Load configuration from `FILE`\",\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nWill result in help output like:\n\n```\n--config FILE, -c FILE   Load configuration from FILE\n```\n\nNote that only the first placeholder is used. Subsequent back-quoted words will\nbe left as-is.\n\n#### Alternate Names\n\nYou can set alternate (or short) names for flags by providing a comma-delimited\nlist for the `Name`. e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;lang value, &#45;l value.*language for the greeting.*default: \\\"english\\\"\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name: \"lang, l\",\n      Value: \"english\",\n      Usage: \"language for the greeting\",\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nThat flag can then be set with `--lang spanish` or `-l spanish`. Note that\ngiving two different forms of the same flag in the same command invocation is an\nerror.\n\n#### Ordering\n\nFlags for the application and commands are shown in the order they are defined.\nHowever, it's possible to sort them from outside this library by using `FlagsByName`\nor `CommandsByName` with `sort`.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"add a task to the list\\n.*complete a task on the list\\n.*\\n\\n.*\\n.*Load configuration from FILE\\n.*Language for the greeting.*\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n  \"sort\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name: \"lang, l\",\n      Value: \"english\",\n      Usage: \"Language for the greeting\",\n    },\n    cli.StringFlag{\n      Name: \"config, c\",\n      Usage: \"Load configuration from `FILE`\",\n    },\n  }\n\n  app.Commands = []cli.Command{\n    {\n      Name:    \"complete\",\n      Aliases: []string{\"c\"},\n      Usage:   \"complete a task on the list\",\n      Action:  func(c *cli.Context) error {\n        return nil\n      },\n    },\n    {\n      Name:    \"add\",\n      Aliases: []string{\"a\"},\n      Usage:   \"add a task to the list\",\n      Action:  func(c *cli.Context) error {\n        return nil\n      },\n    },\n  }\n\n  sort.Sort(cli.FlagsByName(app.Flags))\n  sort.Sort(cli.CommandsByName(app.Commands))\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nWill result in help output like:\n\n```\n--config FILE, -c FILE  Load configuration from FILE\n--lang value, -l value  Language for the greeting (default: \"english\")\n```\n\n#### Values from the Environment\n\nYou can also have the default value set from the environment via `EnvVar`.  e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"language for the greeting.*APP_LANG\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name: \"lang, l\",\n      Value: \"english\",\n      Usage: \"language for the greeting\",\n      EnvVar: \"APP_LANG\",\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nThe `EnvVar` may also be given as a comma-delimited \"cascade\", where the first\nenvironment variable that resolves is used as the default.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name: \"lang, l\",\n      Value: \"english\",\n      Usage: \"language for the greeting\",\n      EnvVar: \"LEGACY_COMPAT_LANG,APP_LANG,LANG\",\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\n#### Values from files\n\nYou can also have the default value set from file via `FilePath`.  e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"password for the mysql database\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Flags = []cli.Flag {\n    cli.StringFlag{\n      Name: \"password, p\",\n      Usage: \"password for the mysql database\",\n      FilePath: \"/etc/mysql/password\",\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nNote that default values set from file (e.g. `FilePath`) take precedence over\ndefault values set from the environment (e.g. `EnvVar`).\n\n#### Values from alternate input sources (YAML, TOML, and others)\n\nThere is a separate package altsrc that adds support for getting flag values\nfrom other file input sources.\n\nCurrently supported input source formats:\n* YAML\n* JSON\n* TOML\n\nIn order to get values for a flag from an alternate input source the following\ncode would be added to wrap an existing cli.Flag like below:\n\n``` go\n  altsrc.NewIntFlag(cli.IntFlag{Name: \"test\"})\n```\n\nInitialization must also occur for these flags. Below is an example initializing\ngetting data from a yaml file below.\n\n``` go\n  command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc(\"load\"))\n```\n\nThe code above will use the \"load\" string as a flag name to get the file name of\na yaml file from the cli.Context.  It will then use that file name to initialize\nthe yaml input source for any flags that are defined on that command.  As a note\nthe \"load\" flag used would also have to be defined on the command flags in order\nfor this code snippet to work.\n\nCurrently only YAML, JSON, and TOML files are supported but developers can add support\nfor other input sources by implementing the altsrc.InputSourceContext for their\ngiven sources.\n\nHere is a more complete sample of a command using YAML support:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45&#45;test value.*default: 0\"\n} -->\n``` go\npackage notmain\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n  \"github.com/urfave/cli/altsrc\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  flags := []cli.Flag{\n    altsrc.NewIntFlag(cli.IntFlag{Name: \"test\"}),\n    cli.StringFlag{Name: \"load\"},\n  }\n\n  app.Action = func(c *cli.Context) error {\n    fmt.Println(\"yaml ist rad\")\n    return nil\n  }\n\n  app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc(\"load\"))\n  app.Flags = flags\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\n#### Precedence\n\nThe precedence for flag value sources is as follows (highest to lowest):\n\n0. Command line flag value from user\n0. Environment variable (if specified)\n0. Configuration file (if specified)\n0. Default defined on the flag\n"
  },
  {
    "path": "docs/v1/examples/generated-help-text.md",
    "content": "---\ntags:\n  - v1\n---\n\nThe default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked\nby the cli internals in order to print generated help text for the app, command,\nor subcommand, and break execution.\n\n#### Customization\n\nAll of the help text generation may be customized, and at multiple levels.  The\ntemplates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and\n`SubcommandHelpTemplate` which may be reassigned or augmented, and full override\nis possible by assigning a compatible func to the `cli.HelpPrinter` variable,\ne.g.:\n\n<!-- {\n  \"output\": \"Ha HA.  I pwnd the help!!1\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"io\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  // EXAMPLE: Append to an existing template\n  cli.AppHelpTemplate = fmt.Sprintf(`%s\n\nWEBSITE: http://awesometown.example.com\n\nSUPPORT: support@awesometown.example.com\n\n`, cli.AppHelpTemplate)\n\n  // EXAMPLE: Override a template\n  cli.AppHelpTemplate = `NAME:\n   {{.Name}} - {{.Usage}}\nUSAGE:\n   {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}\n   {{if len .Authors}}\nAUTHOR:\n   {{range .Authors}}{{ . }}{{end}}\n   {{end}}{{if .Commands}}\nCOMMANDS:\n{{range .Commands}}{{if not .HideHelp}}   {{join .Names \", \"}}{{ \"\\t\"}}{{.Usage}}{{ \"\\n\" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}\nGLOBAL OPTIONS:\n   {{range .VisibleFlags}}{{.}}\n   {{end}}{{end}}{{if .Copyright }}\nCOPYRIGHT:\n   {{.Copyright}}\n   {{end}}{{if .Version}}\nVERSION:\n   {{.Version}}\n   {{end}}\n`\n\n  // EXAMPLE: Replace the `HelpPrinter` func\n  cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {\n    fmt.Println(\"Ha HA.  I pwnd the help!!1\")\n  }\n\n  err := cli.NewApp().Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nThe default flag may be customized to something other than `-h/--help` by\nsetting `cli.HelpFlag`, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45halp\"],\n  \"output\": \"haaaaalp.*HALP\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  cli.HelpFlag = cli.BoolFlag{\n    Name: \"halp, haaaaalp\",\n    Usage: \"HALP\",\n    EnvVar: \"SHOW_HALP,HALPPLZ\",\n  }\n\n  err := cli.NewApp().Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n"
  },
  {
    "path": "docs/v1/examples/greet.md",
    "content": "---\ntags:\n  - v1\n---\n\nBeing a programmer can be a lonely job. Thankfully by the power of automation\nthat is not the case! Let's create a greeter app to fend off our demons of\nloneliness!\n\nStart by creating a directory named `greet`, and within it, add a file,\n`greet.go` with the following code in it:\n\n<!-- {\n  \"output\": \"Hello friend!\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n  app.Name = \"greet\"\n  app.Usage = \"fight the loneliness!\"\n  app.Action = func(c *cli.Context) error {\n    fmt.Println(\"Hello friend!\")\n    return nil\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nInstall our command to the `$GOPATH/bin` directory:\n\n```\n$ go install\n```\n\nFinally run our new command:\n\n```\n$ greet\nHello friend!\n```\n\ncli also generates neat help text:\n\n```\n$ greet help\nNAME:\n    greet - fight the loneliness!\n\nUSAGE:\n    greet [global options] command [command options] [arguments...]\n\nVERSION:\n    0.0.0\n\nCOMMANDS:\n    help, h  Shows a list of commands or help for one command\n\nGLOBAL OPTIONS\n    --version Shows version information\n```\n"
  },
  {
    "path": "docs/v1/examples/subcommands-categories.md",
    "content": "---\ntags:\n  - v1\n---\n\nFor additional organization in apps that have many subcommands, you can\nassociate a category for each command to group them together in the help\noutput.\n\nE.g.\n\n```go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Commands = []cli.Command{\n    {\n      Name: \"noop\",\n    },\n    {\n      Name:     \"add\",\n      Category: \"Template actions\",\n    },\n    {\n      Name:     \"remove\",\n      Category: \"Template actions\",\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nWill include:\n\n```\nCOMMANDS:\n  noop\n\n  Template actions:\n    add\n    remove\n```\n"
  },
  {
    "path": "docs/v1/examples/subcommands.md",
    "content": "---\ntags:\n  - v1\n---\n\nSubcommands can be defined for a more git-like command line app.\n\n<!-- {\n  \"args\": [\"template\", \"add\"],\n  \"output\": \"new task template: .+\"\n} -->\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n\n  app.Commands = []cli.Command{\n    {\n      Name:    \"add\",\n      Aliases: []string{\"a\"},\n      Usage:   \"add a task to the list\",\n      Action:  func(c *cli.Context) error {\n        fmt.Println(\"added task: \", c.Args().First())\n        return nil\n      },\n    },\n    {\n      Name:    \"complete\",\n      Aliases: []string{\"c\"},\n      Usage:   \"complete a task on the list\",\n      Action:  func(c *cli.Context) error {\n        fmt.Println(\"completed task: \", c.Args().First())\n        return nil\n      },\n    },\n    {\n      Name:        \"template\",\n      Aliases:     []string{\"t\"},\n      Usage:       \"options for task templates\",\n      Subcommands: []cli.Command{\n        {\n          Name:  \"add\",\n          Usage: \"add a new template\",\n          Action: func(c *cli.Context) error {\n            fmt.Println(\"new task template: \", c.Args().First())\n            return nil\n          },\n        },\n        {\n          Name:  \"remove\",\n          Usage: \"remove an existing template\",\n          Action: func(c *cli.Context) error {\n            fmt.Println(\"removed task template: \", c.Args().First())\n            return nil\n          },\n        },\n      },\n    },\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n"
  },
  {
    "path": "docs/v1/examples/version-flag.md",
    "content": "---\ntags:\n  - v1\n---\n\nThe default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which\nis checked by the cli internals in order to print the `App.Version` via\n`cli.VersionPrinter` and break execution.\n\n#### Customization\n\nThe default flag may be customized to something other than `-v/--version` by\nsetting `cli.VersionFlag`, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45print-version\"],\n  \"output\": \"partay version 19\\\\.99\\\\.0\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  cli.VersionFlag = cli.BoolFlag{\n    Name: \"print-version, V\",\n    Usage: \"print only the version\",\n  }\n\n  app := cli.NewApp()\n  app.Name = \"partay\"\n  app.Version = \"19.99.0\"\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nAlternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45version\"],\n  \"output\": \"version=19\\\\.99\\\\.0 revision=fafafaf\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nvar (\n  Revision = \"fafafaf\"\n)\n\nfunc main() {\n  cli.VersionPrinter = func(c *cli.Context) {\n    fmt.Printf(\"version=%s revision=%s\\n\", c.App.Version, Revision)\n  }\n\n  app := cli.NewApp()\n  app.Name = \"partay\"\n  app.Version = \"19.99.0\"\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\n#### Full API Example\n\n**Notice**: This is a contrived (functioning) example meant strictly for API\ndemonstration purposes.  Use of one's imagination is encouraged.\n\n<!-- {\n  \"output\": \"made it!\\nPhew!\"\n} -->\n``` go\npackage main\n\nimport (\n  \"errors\"\n  \"flag\"\n  \"fmt\"\n  \"io\"\n  \"io/ioutil\"\n  \"os\"\n  \"time\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc init() {\n  cli.AppHelpTemplate += \"\\nCUSTOMIZED: you bet ur muffins\\n\"\n  cli.CommandHelpTemplate += \"\\nYMMV\\n\"\n  cli.SubcommandHelpTemplate += \"\\nor something\\n\"\n\n  cli.HelpFlag = cli.BoolFlag{Name: \"halp\"}\n  cli.BashCompletionFlag = cli.BoolFlag{Name: \"compgen\", Hidden: true}\n  cli.VersionFlag = cli.BoolFlag{Name: \"print-version, V\"}\n\n  cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {\n    fmt.Fprintf(w, \"best of luck to you\\n\")\n  }\n  cli.VersionPrinter = func(c *cli.Context) {\n    fmt.Fprintf(c.App.Writer, \"version=%s\\n\", c.App.Version)\n  }\n  cli.OsExiter = func(c int) {\n    fmt.Fprintf(cli.ErrWriter, \"refusing to exit %d\\n\", c)\n  }\n  cli.ErrWriter = ioutil.Discard\n  cli.FlagStringer = func(fl cli.Flag) string {\n    return fmt.Sprintf(\"\\t\\t%s\", fl.GetName())\n  }\n}\n\ntype hexWriter struct{}\n\nfunc (w *hexWriter) Write(p []byte) (int, error) {\n  for _, b := range p {\n    fmt.Printf(\"%x\", b)\n  }\n  fmt.Printf(\"\\n\")\n\n  return len(p), nil\n}\n\ntype genericType struct{\n  s string\n}\n\nfunc (g *genericType) Set(value string) error {\n  g.s = value\n  return nil\n}\n\nfunc (g *genericType) String() string {\n  return g.s\n}\n\nfunc main() {\n  app := cli.NewApp()\n  app.Name = \"kənˈtrīv\"\n  app.Version = \"19.99.0\"\n  app.Compiled = time.Now()\n  app.Authors = []cli.Author{\n    cli.Author{\n      Name:  \"Example Human\",\n      Email: \"human@example.com\",\n    },\n  }\n  app.Copyright = \"(c) 1999 Serious Enterprise\"\n  app.HelpName = \"contrive\"\n  app.Usage = \"demonstrate available API\"\n  app.UsageText = \"contrive - demonstrating the available API\"\n  app.ArgsUsage = \"[args and such]\"\n  app.Commands = []cli.Command{\n    cli.Command{\n      Name:        \"doo\",\n      Aliases:     []string{\"do\"},\n      Category:    \"motion\",\n      Usage:       \"do the doo\",\n      UsageText:   \"doo - does the dooing\",\n      Description: \"no really, there is a lot of dooing to be done\",\n      ArgsUsage:   \"[arrgh]\",\n      Flags: []cli.Flag{\n        cli.BoolFlag{Name: \"forever, forevvarr\"},\n      },\n      Subcommands: cli.Commands{\n        cli.Command{\n          Name:   \"wop\",\n          Action: wopAction,\n        },\n      },\n      SkipFlagParsing: false,\n      HideHelp:        false,\n      Hidden:          false,\n      HelpName:        \"doo!\",\n      BashComplete: func(c *cli.Context) {\n        fmt.Fprintf(c.App.Writer, \"--better\\n\")\n      },\n      Before: func(c *cli.Context) error {\n        fmt.Fprintf(c.App.Writer, \"brace for impact\\n\")\n        return nil\n      },\n      After: func(c *cli.Context) error {\n        fmt.Fprintf(c.App.Writer, \"did we lose anyone?\\n\")\n        return nil\n      },\n      Action: func(c *cli.Context) error {\n        c.Command.FullName()\n        c.Command.HasName(\"wop\")\n        c.Command.Names()\n        c.Command.VisibleFlags()\n        fmt.Fprintf(c.App.Writer, \"dodododododoodododddooooododododooo\\n\")\n        if c.Bool(\"forever\") {\n          c.Command.Run(c)\n        }\n        return nil\n      },\n      OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {\n        fmt.Fprintf(c.App.Writer, \"for shame\\n\")\n        return err\n      },\n    },\n  }\n  app.Flags = []cli.Flag{\n    cli.BoolFlag{Name: \"fancy\"},\n    cli.BoolTFlag{Name: \"fancier\"},\n    cli.DurationFlag{Name: \"howlong, H\", Value: time.Second * 3},\n    cli.Float64Flag{Name: \"howmuch\"},\n    cli.GenericFlag{Name: \"wat\", Value: &genericType{}},\n    cli.Int64Flag{Name: \"longdistance\"},\n    cli.Int64SliceFlag{Name: \"intervals\"},\n    cli.IntFlag{Name: \"distance\"},\n    cli.IntSliceFlag{Name: \"times\"},\n    cli.StringFlag{Name: \"dance-move, d\"},\n    cli.StringSliceFlag{Name: \"names, N\"},\n    cli.UintFlag{Name: \"age\"},\n    cli.Uint64Flag{Name: \"bigage\"},\n  }\n  app.EnableBashCompletion = true\n  app.UseShortOptionHandling = true\n  app.HideHelp = false\n  app.HideVersion = false\n  app.BashComplete = func(c *cli.Context) {\n    fmt.Fprintf(c.App.Writer, \"lipstick\\nkiss\\nme\\nlipstick\\nringo\\n\")\n  }\n  app.Before = func(c *cli.Context) error {\n    fmt.Fprintf(c.App.Writer, \"HEEEERE GOES\\n\")\n    return nil\n  }\n  app.After = func(c *cli.Context) error {\n    fmt.Fprintf(c.App.Writer, \"Phew!\\n\")\n    return nil\n  }\n  app.CommandNotFound = func(c *cli.Context, command string) {\n    fmt.Fprintf(c.App.Writer, \"Thar be no %q here.\\n\", command)\n  }\n  app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {\n    if isSubcommand {\n      return err\n    }\n\n    fmt.Fprintf(c.App.Writer, \"WRONG: %#v\\n\", err)\n    return nil\n  }\n  app.Action = func(c *cli.Context) error {\n    cli.DefaultAppComplete(c)\n    cli.HandleExitCoder(errors.New(\"not an exit coder, though\"))\n    cli.ShowAppHelp(c)\n    cli.ShowCommandCompletions(c, \"nope\")\n    cli.ShowCommandHelp(c, \"also-nope\")\n    cli.ShowCompletions(c)\n    cli.ShowSubcommandHelp(c)\n    cli.ShowVersion(c)\n\n    categories := c.App.Categories()\n    categories.AddCommand(\"sounds\", cli.Command{\n      Name: \"bloop\",\n    })\n\n    for _, category := range c.App.Categories() {\n      fmt.Fprintf(c.App.Writer, \"%s\\n\", category.Name)\n      fmt.Fprintf(c.App.Writer, \"%#v\\n\", category.Commands)\n      fmt.Fprintf(c.App.Writer, \"%#v\\n\", category.VisibleCommands())\n    }\n\n    fmt.Printf(\"%#v\\n\", c.App.Command(\"doo\"))\n    if c.Bool(\"infinite\") {\n      c.App.Run([]string{\"app\", \"doo\", \"wop\"})\n    }\n\n    if c.Bool(\"forevar\") {\n      c.App.RunAsSubcommand(c)\n    }\n    c.App.Setup()\n    fmt.Printf(\"%#v\\n\", c.App.VisibleCategories())\n    fmt.Printf(\"%#v\\n\", c.App.VisibleCommands())\n    fmt.Printf(\"%#v\\n\", c.App.VisibleFlags())\n\n    fmt.Printf(\"%#v\\n\", c.Args().First())\n    if len(c.Args()) > 0 {\n      fmt.Printf(\"%#v\\n\", c.Args()[1])\n    }\n    fmt.Printf(\"%#v\\n\", c.Args().Present())\n    fmt.Printf(\"%#v\\n\", c.Args().Tail())\n\n    set := flag.NewFlagSet(\"contrive\", 0)\n    nc := cli.NewContext(c.App, set, c)\n\n    fmt.Printf(\"%#v\\n\", nc.Args())\n    fmt.Printf(\"%#v\\n\", nc.Bool(\"nope\"))\n    fmt.Printf(\"%#v\\n\", nc.BoolT(\"nerp\"))\n    fmt.Printf(\"%#v\\n\", nc.Duration(\"howlong\"))\n    fmt.Printf(\"%#v\\n\", nc.Float64(\"hay\"))\n    fmt.Printf(\"%#v\\n\", nc.Generic(\"bloop\"))\n    fmt.Printf(\"%#v\\n\", nc.Int64(\"bonk\"))\n    fmt.Printf(\"%#v\\n\", nc.Int64Slice(\"burnks\"))\n    fmt.Printf(\"%#v\\n\", nc.Int(\"bips\"))\n    fmt.Printf(\"%#v\\n\", nc.IntSlice(\"blups\"))\n    fmt.Printf(\"%#v\\n\", nc.String(\"snurt\"))\n    fmt.Printf(\"%#v\\n\", nc.StringSlice(\"snurkles\"))\n    fmt.Printf(\"%#v\\n\", nc.Uint(\"flub\"))\n    fmt.Printf(\"%#v\\n\", nc.Uint64(\"florb\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalBool(\"global-nope\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalBoolT(\"global-nerp\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalDuration(\"global-howlong\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalFloat64(\"global-hay\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalGeneric(\"global-bloop\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalInt(\"global-bips\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalIntSlice(\"global-blups\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalString(\"global-snurt\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalStringSlice(\"global-snurkles\"))\n\n    fmt.Printf(\"%#v\\n\", nc.FlagNames())\n    fmt.Printf(\"%#v\\n\", nc.GlobalFlagNames())\n    fmt.Printf(\"%#v\\n\", nc.GlobalIsSet(\"wat\"))\n    fmt.Printf(\"%#v\\n\", nc.GlobalSet(\"wat\", \"nope\"))\n    fmt.Printf(\"%#v\\n\", nc.NArg())\n    fmt.Printf(\"%#v\\n\", nc.NumFlags())\n    fmt.Printf(\"%#v\\n\", nc.Parent())\n\n    nc.Set(\"wat\", \"also-nope\")\n\n    ec := cli.NewExitError(\"ohwell\", 86)\n    fmt.Fprintf(c.App.Writer, \"%d\", ec.ExitCode())\n    fmt.Printf(\"made it!\\n\")\n    return nil\n  }\n\n  if os.Getenv(\"HEXY\") != \"\" {\n    app.Writer = &hexWriter{}\n    app.ErrWriter = &hexWriter{}\n  }\n\n  app.Metadata = map[string]interface{}{\n    \"layers\":     \"many\",\n    \"explicable\": false,\n    \"whatever-values\": 19.99,\n  }\n\n\n  // ignore error so we don't exit non-zero and break gfmrun README example tests\n  _ = app.Run(os.Args)\n}\n\nfunc wopAction(c *cli.Context) error {\n  fmt.Fprintf(c.App.Writer, \":wave: over here, eh\\n\")\n  return nil\n}\n```\n"
  },
  {
    "path": "docs/v1/getting-started.md",
    "content": "---\ntags:\n  - v1\n---\n\nOne of the philosophies behind cli is that an API should be playful and full of\ndiscovery. So a cli app can be as little as one line of code in `main()`.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"A new cli application\"\n} -->\n``` go\npackage main\n\nimport (\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  err := cli.NewApp().Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nThis app will run and show help text, but is not very useful. Let's give an\naction to execute and some help documentation:\n\n<!-- {\n  \"output\": \"boom! I say!\"\n} -->\n``` go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"os\"\n\n  \"github.com/urfave/cli\"\n)\n\nfunc main() {\n  app := cli.NewApp()\n  app.Name = \"boom\"\n  app.Usage = \"make an explosive entrance\"\n  app.Action = func(c *cli.Context) error {\n    fmt.Println(\"boom! I say!\")\n    return nil\n  }\n\n  err := app.Run(os.Args)\n  if err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\nRunning this already gives you a ton of functionality, plus support for things\nlike subcommands and flags, which are covered below.\n"
  },
  {
    "path": "docs/v1/migrating-to-v2.md",
    "content": "---\ntags:\n  - v1\n---\n\nThere are a small set of breaking changes between v1 and v2.\nConverting is relatively straightforward and typically takes less than\nan hour. Specific steps are included in\n[Migration Guide: v1 to v2](../migrate-v1-to-v2.md).\n"
  },
  {
    "path": "docs/v2/examples/arguments.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nYou can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:\n\n<!-- {\n  \"output\": \"Hello \\\"\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tfmt.Printf(\"Hello %q\", cCtx.Args().Get(0))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v2/examples/bash-completions.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nYou can enable completion commands by setting the `EnableBashCompletion` flag on\nthe `App` object to `true`.  By default, this setting will allow auto-completion\nfor an app's subcommands, but you can write your own completion methods for the\nApp or its subcommands as well.\n\n#### Default auto-completion\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tEnableBashCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Println(\"added task: \", cCtx.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cCtx.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"template\",\n\t\t\t\tAliases: []string{\"t\"},\n\t\t\t\tUsage:   \"options for task templates\",\n\t\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"add\",\n\t\t\t\t\t\tUsage: \"add a new template\",\n\t\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t\tfmt.Println(\"new task template: \", cCtx.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"remove\",\n\t\t\t\t\t\tUsage: \"remove an existing template\",\n\t\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t\tfmt.Println(\"removed task template: \", cCtx.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n![](../images/default-bash-autocomplete.gif)\n\n#### Custom auto-completion\n<!-- {\n  \"args\": [\"complete\", \"&#45;&#45;generate&#45;bash&#45;completion\"],\n  \"output\": \"laundry\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\ttasks := []string{\"cook\", \"clean\", \"laundry\", \"eat\", \"sleep\", \"code\"}\n\n\tapp := &cli.App{\n\t\tEnableBashCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cCtx.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tBashComplete: func(cCtx *cli.Context) {\n\t\t\t\t\t// This will complete if no args are passed\n\t\t\t\t\tif cCtx.NArg() > 0 {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tfor _, t := range tasks {\n\t\t\t\t\t\tfmt.Println(t)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n![](../images/custom-bash-autocomplete.gif)\n\n#### Enabling\n\nTo enable auto-completion for the current shell session, a bash script,\n`autocomplete/bash_autocomplete` is included in this repo.\n\nTo use `autocomplete/bash_autocomplete` set an environment variable named `PROG`\nto the name of your program and then `source` the\n`autocomplete/bash_autocomplete` file.\n\nFor example, if your cli program is called `myprogram`:\n\n```sh-session\n$ PROG=myprogram source path/to/cli/autocomplete/bash_autocomplete\n```\n\nAuto-completion is now enabled for the current shell, but will not persist into\na new shell.\n\n#### Distribution and Persistent Autocompletion\n\nCopy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename\nit to the name of the program you wish to add autocomplete support for (or\nautomatically install it there if you are distributing a package). Don't forget\nto source the file or restart your shell to activate the auto-completion.\n\n```sh-session\n$ sudo cp path/to/autocomplete/bash_autocomplete /etc/bash_completion.d/<myprogram>\n$ source /etc/bash_completion.d/<myprogram>\n```\n\nAlternatively, you can just document that users should `source` the generic\n`autocomplete/bash_autocomplete` and set `$PROG` within their bash configuration\nfile, adding these lines:\n\n```sh-session\n$ PROG=<myprogram>\n$ source path/to/cli/autocomplete/bash_autocomplete\n```\n\nKeep in mind that if they are enabling auto-completion for more than one\nprogram, they will need to set `PROG` and source\n`autocomplete/bash_autocomplete` for each program, like so:\n\n```sh-session\n$ PROG=<program1>\n$ source path/to/cli/autocomplete/bash_autocomplete\n\n$ PROG=<program2>\n$ source path/to/cli/autocomplete/bash_autocomplete\n```\n\n#### Customization\n\nThe default shell completion flag (`--generate-bash-completion`) is defined as\n`cli.EnableBashCompletion`, and may be redefined if desired, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45;generate&#45;bash&#45;completion\"],\n  \"output\": \"wat\\nhelp\\nh\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tEnableBashCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName: \"wat\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n#### ZSH Support\n\nAuto-completion for ZSH is also supported using the\n`autocomplete/zsh_autocomplete` file included in this repo. One environment\nvariable is used, `PROG`.  Set `PROG` to the program name as before, and then\n`source path/to/autocomplete/zsh_autocomplete`.  Adding the following lines to\nyour ZSH configuration file (usually `.zshrc`) will allow the auto-completion to\npersist across new shells:\n\n```sh-session\n$ PROG=<myprogram>\n$ source path/to/autocomplete/zsh_autocomplete\n```\n\n#### ZSH default auto-complete example\n![](../images/default-zsh-autocomplete.gif)\n\n#### ZSH custom auto-complete example\n![](../images/custom-zsh-autocomplete.gif)\n\n#### PowerShell Support\n\nAuto-completion for PowerShell is also supported using the\n`autocomplete/powershell_autocomplete.ps1` file included in this repo.\n\nRename the script to `<my program>.ps1` and move it anywhere in your file\nsystem.  The location of script does not matter, only the file name of the\nscript has to match the your program's binary name.\n\nTo activate it, enter:\n\n```powershell\n& path/to/autocomplete/<my program>.ps1\n```\n\nTo persist across new shells, open the PowerShell profile (with `code $profile`\nor `notepad $profile`) and add the line:\n\n```powershell\n& path/to/autocomplete/<my program>.ps1\n```\n"
  },
  {
    "path": "docs/v2/examples/combining-short-options.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nTraditional use of options using their shortnames look like this:\n\n```sh-session\n$ cmd -s -o -m \"Some message\"\n```\n\nSuppose you want users to be able to combine options with their shortnames. This\ncan be done using the `UseShortOptionHandling` bool in your app configuration,\nor for individual commands by attaching it to the command configuration. For\nexample:\n\n<!-- {\n  \"args\": [\"short\", \"&#45;som\", \"Some message\"],\n  \"output\": \"serve: true\\noption: true\\nmessage: Some message\\n\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tUseShortOptionHandling: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:  \"short\",\n\t\t\t\tUsage: \"complete a task on the list\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t\t\t\t&cli.BoolFlag{Name: \"option\", Aliases: []string{\"o\"}},\n\t\t\t\t\t&cli.StringFlag{Name: \"message\", Aliases: []string{\"m\"}},\n\t\t\t\t},\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Println(\"serve:\", cCtx.Bool(\"serve\"))\n\t\t\t\t\tfmt.Println(\"option:\", cCtx.Bool(\"option\"))\n\t\t\t\t\tfmt.Println(\"message:\", cCtx.String(\"message\"))\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIf your program has any number of bool flags such as `serve` and `option`, and\noptionally one non-bool flag `message`, with the short options of `-s`, `-o`,\nand `-m` respectively, setting `UseShortOptionHandling` will also support the\nfollowing syntax:\n\n```sh-session\n$ cmd -som \"Some message\"\n```\n\nIf you enable `UseShortOptionHandling`, then you must not use any flags that\nhave a single leading `-` or this will result in failures. For example,\n`-option` can no longer be used. Flags with two leading dashes (such as\n`--options`) are still valid.\n"
  },
  {
    "path": "docs/v2/examples/exit-codes.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nCalling `App.Run` will not automatically call `os.Exit`, which means that by\ndefault the exit code will \"fall through\" to being `0`.  An explicit exit code\nmay be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a\n`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:\n<!-- {\n  \"error\": \"Ginger croutons are not in the soup\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{\n\t\t\t\tName:  \"ginger-crouton\",\n\t\t\t\tUsage: \"is it in the soup?\",\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx *cli.Context) error {\n\t\t\tif !ctx.Bool(\"ginger-crouton\") {\n\t\t\t\treturn cli.Exit(\"Ginger croutons are not in the soup\", 86)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v2/examples/flags.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nSetting and querying flags is simple.\n\n<!-- {\n  \"output\": \"Hello Nefertiti\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:  \"lang\",\n\t\t\t\tValue: \"english\",\n\t\t\t\tUsage: \"language for the greeting\",\n\t\t\t},\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tname := \"Nefertiti\"\n\t\t\tif cCtx.NArg() > 0 {\n\t\t\t\tname = cCtx.Args().Get(0)\n\t\t\t}\n\t\t\tif cCtx.String(\"lang\") == \"spanish\" {\n\t\t\t\tfmt.Println(\"Hola\", name)\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Hello\", name)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nYou can also set a destination variable for a flag, to which the content will be\nscanned. Note that if the `Value` is set for the flag, it will be shown as default,\nand destination will be set to this value before parsing flag on the command line.\n\n<!-- {\n  \"output\": \"Hello someone\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tvar language string\n\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:        \"lang\",\n\t\t\t\tValue:       \"english\",\n\t\t\t\tUsage:       \"language for the greeting\",\n\t\t\t\tDestination: &language,\n\t\t\t},\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tname := \"someone\"\n\t\t\tif cCtx.NArg() > 0 {\n\t\t\t\tname = cCtx.Args().Get(0)\n\t\t\t}\n\t\t\tif language == \"spanish\" {\n\t\t\t\tfmt.Println(\"Hola\", name)\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Hello\", name)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nSee full list of flags at https://pkg.go.dev/github.com/urfave/cli/v2\n\nFor bool flags you can specify the flag multiple times to get a count(e.g -v -v -v or -vvv)\n\n> If you want to support the `-vvv` flag, you need to set `App.UseShortOptionHandling`.\n\n<!-- {\n  \"args\": [\"&#45;&#45;foo\", \"&#45;&#45;foo\", \"&#45;fff\",  \"&#45;f\"],\n  \"output\": \"count 6\"  \n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tvar count int\n\n\tapp := &cli.App{\n\t\tUseShortOptionHandling: true,\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{\n\t\t\t\tName:        \"foo\",\n\t\t\t\tUsage:       \"foo greeting\",\n\t\t\t\tAliases:     []string{\"f\"},\n\t\t\t\tCount: &count,\n\t\t\t},\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tfmt.Println(\"count\", count)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n#### Placeholder Values\n\nSometimes it's useful to specify a flag's value within the usage string itself.\nSuch placeholders are indicated with back quotes.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;config FILE, &#45;c FILE\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"config\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"Load configuration from `FILE`\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\n--config FILE, -c FILE   Load configuration from FILE\n```\n\nNote that only the first placeholder is used. Subsequent back-quoted words will\nbe left as-is.\n\n#### Alternate Names\n\nYou can set alternate (or short) names for flags by providing a comma-delimited\nlist for the `Name`. e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;lang value, &#45;l value.*language for the greeting.*default: \\\"english\\\"\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"language for the greeting\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nThat flag can then be set with `--lang spanish` or `-l spanish`. Note that\ngiving two different forms of the same flag in the same command invocation is an\nerror.\n\n#### Multiple Values per Single Flag\n\nUsing a slice flag allows you to pass multiple values for a single flag; the values will be provided as a slice:\n\n- `Int64SliceFlag`\n- `IntSliceFlag`\n- `StringSliceFlag`\n\n<!-- {\n  \"args\": [\"&#45;&#45;greeting Hello\", \"&#45;&#45;greeting Hola\"],\n  \"output\": \"Hello, Hola\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringSliceFlag{\n\t\t\t\tName:  \"greeting\",\n\t\t\t\tUsage: \"Pass multiple greetings\",\n\t\t\t},\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tfmt.Println(strings.Join(cCtx.StringSlice(\"greeting\"), `, `))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nMultiple values need to be passed as separate, repeating flags, e.g. `--greeting Hello --greeting Hola`.\n\n#### Ordering\n\nFlags for the application and commands are shown in the order they are defined.\nHowever, it's possible to sort them from outside this library by using `FlagsByName`\nor `CommandsByName` with `sort`.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \".*Load configuration from FILE\\n.*\\n.*Language for the greeting.*\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"Language for the greeting\",\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"config\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"Load configuration from `FILE`\",\n\t\t\t},\n\t\t},\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(*cli.Context) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(*cli.Context) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tsort.Sort(cli.FlagsByName(app.Flags))\n\tsort.Sort(cli.CommandsByName(app.Commands))\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\n--config FILE, -c FILE  Load configuration from FILE\n--lang value, -l value  Language for the greeting (default: \"english\")\n```\n\n#### Values from the Environment\n\nYou can also have the default value set from the environment via `EnvVars`.  e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"language for the greeting.*APP_LANG\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"language for the greeting\",\n\t\t\t\tEnvVars: []string{\"APP_LANG\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIf `EnvVars` contains more than one string, the first environment variable that\nresolves is used.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"language for the greeting\",\n\t\t\t\tEnvVars: []string{\"LEGACY_COMPAT_LANG\", \"APP_LANG\", \"LANG\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n#### Values from files\n\nYou can also have the default value set from file via `FilePath`.  e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"password for the mysql database\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:     \"password\",\n\t\t\t\tAliases:  []string{\"p\"},\n\t\t\t\tUsage:    \"password for the mysql database\",\n\t\t\t\tFilePath: \"/etc/mysql/password\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nNote that default values set from file (e.g. `FilePath`) take precedence over\ndefault values set from the environment (e.g. `EnvVar`).\n\n#### Values from alternate input sources (YAML, TOML, and others)\n\nThere is a separate package altsrc that adds support for getting flag values\nfrom other file input sources.\n\nCurrently supported input source formats:\n\n- YAML\n- JSON\n- TOML\n\nIn order to get values for a flag from an alternate input source the following\ncode would be added to wrap an existing cli.Flag like below:\n\n```go\n  // --- >8 ---\n  altsrc.NewIntFlag(&cli.IntFlag{Name: \"test\"})\n```\n\nInitialization must also occur for these flags. Below is an example initializing\ngetting data from a yaml file below.\n\n```go\n  // --- >8 ---\n  command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc(\"load\"))\n```\n\nThe code above will use the \"load\" string as a flag name to get the file name of\na yaml file from the cli.Context.  It will then use that file name to initialize\nthe yaml input source for any flags that are defined on that command.  As a note\nthe \"load\" flag used would also have to be defined on the command flags in order\nfor this code snippet to work.\n\nCurrently only YAML, JSON, and TOML files are supported but developers can add\nsupport for other input sources by implementing the altsrc.InputSourceContext\nfor their given sources.\n\nHere is a more complete sample of a command using YAML support:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45&#45;test value.*default: 0\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n\t\"github.com/urfave/cli/v2/altsrc\"\n)\n\nfunc main() {\n\tflags := []cli.Flag{\n\t\taltsrc.NewIntFlag(&cli.IntFlag{Name: \"test\"}),\n\t\t&cli.StringFlag{Name: \"load\"},\n\t}\n\n\tapp := &cli.App{\n\t\tAction: func(*cli.Context) error {\n\t\t\tfmt.Println(\"--test value.*default: 0\")\n\t\t\treturn nil\n\t\t},\n\t\tBefore: altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc(\"load\")),\n\t\tFlags:  flags,\n\t}\n\n\tapp.Run(os.Args)\n}\n```\n\n#### Required Flags\n\nYou can make a flag required by setting the `Required` field to `true`. If a user\ndoes not provide a required flag, they will be shown an error message.\n\nTake for example this app that requires the `lang` flag:\n\n<!-- {\n  \"error\": \"Required flag \\\"lang\\\" not set\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:     \"lang\",\n\t\t\t\tValue:    \"english\",\n\t\t\t\tUsage:    \"language for the greeting\",\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\toutput := \"Hello\"\n\t\t\tif cCtx.String(\"lang\") == \"spanish\" {\n\t\t\t\toutput = \"Hola\"\n\t\t\t}\n\t\t\tfmt.Println(output)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIf the app is run without the `lang` flag, the user will see the following message\n\n```\nRequired flag \"lang\" not set\n```\n\n#### Default Values for help output\n\nSometimes it's useful to specify a flag's default help-text value within the\nflag declaration. This can be useful if the default value for a flag is a\ncomputed value. The default value can be set via the `DefaultText` struct field.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;port value\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.IntFlag{\n\t\t\t\tName:        \"port\",\n\t\t\t\tUsage:       \"Use a randomized port\",\n\t\t\t\tValue:       0,\n\t\t\t\tDefaultText: \"random\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\n--port value  Use a randomized port (default: random)\n```\n\n#### Precedence\n\nThe precedence for flag value sources is as follows (highest to lowest):\n\n0. Command line flag value from user\n0. Environment variable (if specified)\n0. Configuration file (if specified)\n0. Default defined on the flag\n\n#### Flag Actions\n\nHandlers can be registered per flag which are triggered after a flag has been processed. \nThis can be used for a variety of purposes, one of which is flag validation\n\n<!-- {\n  \"args\": [\"&#45;&#45;port\",\"70000\"],\n  \"error\": \"Flag port value 70000 out of range[0-65535]\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"fmt\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.IntFlag{\n\t\t\t\tName:        \"port\",\n\t\t\t\tUsage:       \"Use a randomized port\",\n\t\t\t\tValue:       0,\n\t\t\t\tDefaultText: \"random\",\n\t\t\t\tAction: func(ctx *cli.Context, v int) error {\n\t\t\t\t\tif v >= 65536 {\n\t\t\t\t\t\treturn fmt.Errorf(\"Flag port value %v out of range[0-65535]\", v)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\nFlag port value 70000 out of range[0-65535]\n```\n"
  },
  {
    "path": "docs/v2/examples/full-api-example.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\n**Notice**: This is a contrived (functioning) example meant strictly for API\ndemonstration purposes. Use of one's imagination is encouraged.\n\n<!-- {\n  \"output\": \"made it!\\nPhew!\"\n} -->\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc init() {\n\tcli.AppHelpTemplate += \"\\nCUSTOMIZED: you bet ur muffins\\n\"\n\tcli.CommandHelpTemplate += \"\\nYMMV\\n\"\n\tcli.SubcommandHelpTemplate += \"\\nor something\\n\"\n\n\tcli.HelpFlag = &cli.BoolFlag{Name: \"halp\"}\n\tcli.VersionFlag = &cli.BoolFlag{Name: \"print-version\", Aliases: []string{\"V\"}}\n\n\tcli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfmt.Fprintf(w, \"best of luck to you\\n\")\n\t}\n\tcli.VersionPrinter = func(cCtx *cli.Context) {\n\t\tfmt.Fprintf(cCtx.App.Writer, \"version=%s\\n\", cCtx.App.Version)\n\t}\n\tcli.OsExiter = func(cCtx int) {\n\t\tfmt.Fprintf(cli.ErrWriter, \"refusing to exit %d\\n\", cCtx)\n\t}\n\tcli.ErrWriter = ioutil.Discard\n\tcli.FlagStringer = func(fl cli.Flag) string {\n\t\treturn fmt.Sprintf(\"\\t\\t%s\", fl.Names()[0])\n\t}\n}\n\ntype hexWriter struct{}\n\nfunc (w *hexWriter) Write(p []byte) (int, error) {\n\tfor _, b := range p {\n\t\tfmt.Printf(\"%x\", b)\n\t}\n\tfmt.Printf(\"\\n\")\n\n\treturn len(p), nil\n}\n\ntype genericType struct {\n\ts string\n}\n\nfunc (g *genericType) Set(value string) error {\n\tg.s = value\n\treturn nil\n}\n\nfunc (g *genericType) String() string {\n\treturn g.s\n}\n\nfunc main() {\n\tapp := &cli.App{\n\t\tName:     \"kənˈtrīv\",\n\t\tVersion:  \"v19.99.0\",\n\t\tCompiled: time.Now(),\n\t\tAuthors: []*cli.Author{\n\t\t\t&cli.Author{\n\t\t\t\tName:  \"Example Human\",\n\t\t\t\tEmail: \"human@example.com\",\n\t\t\t},\n\t\t},\n\t\tCopyright: \"(c) 1999 Serious Enterprise\",\n\t\tHelpName:  \"contrive\",\n\t\tUsage:     \"demonstrate available API\",\n\t\tUsageText: \"contrive - demonstrating the available API\",\n\t\tArgsUsage: \"[args and such]\",\n\t\tCommands: []*cli.Command{\n\t\t\t&cli.Command{\n\t\t\t\tName:        \"doo\",\n\t\t\t\tAliases:     []string{\"do\"},\n\t\t\t\tCategory:    \"motion\",\n\t\t\t\tUsage:       \"do the doo\",\n\t\t\t\tUsageText:   \"doo - does the dooing\",\n\t\t\t\tDescription: \"no really, there is a lot of dooing to be done\",\n\t\t\t\tArgsUsage:   \"[arrgh]\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"forever\", Aliases: []string{\"forevvarr\"}},\n\t\t\t\t},\n\t\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t\t&cli.Command{\n\t\t\t\t\t\tName:   \"wop\",\n\t\t\t\t\t\tAction: wopAction,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSkipFlagParsing:    false,\n\t\t\t\tHideHelp:           false,\n\t\t\t\tHideHelpCommand:    false,\n\t\t\t\tHidden:             false,\n\t\t\t\tHelpName:           \"doo!\",\n\t\t\t\tBashComplete: func(cCtx *cli.Context) {\n\t\t\t\t\tfmt.Fprintf(cCtx.App.Writer, \"--better\\n\")\n\t\t\t\t},\n\t\t\t\tBefore: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Fprintf(cCtx.App.Writer, \"brace for impact\\n\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tAfter: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Fprintf(cCtx.App.Writer, \"did we lose anyone?\\n\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tcCtx.Command.FullName()\n\t\t\t\t\tcCtx.Command.HasName(\"wop\")\n\t\t\t\t\tcCtx.Command.Names()\n\t\t\t\t\tcCtx.Command.VisibleFlags()\n\t\t\t\t\tfmt.Fprintf(cCtx.App.Writer, \"dodododododoodododddooooododododooo\\n\")\n\t\t\t\t\tif cCtx.Bool(\"forever\") {\n\t\t\t\t\t\tcCtx.Command.Run(cCtx)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tOnUsageError: func(cCtx *cli.Context, err error, isSubcommand bool) error {\n\t\t\t\t\tfmt.Fprintf(cCtx.App.Writer, \"for shame\\n\")\n\t\t\t\t\treturn err\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{Name: \"fancy\"},\n\t\t\t&cli.BoolFlag{Value: true, Name: \"fancier\"},\n\t\t\t&cli.DurationFlag{Name: \"howlong\", Aliases: []string{\"H\"}, Value: time.Second * 3},\n\t\t\t&cli.Float64Flag{Name: \"howmuch\"},\n\t\t\t&cli.GenericFlag{Name: \"wat\", Value: &genericType{}},\n\t\t\t&cli.Int64Flag{Name: \"longdistance\"},\n\t\t\t&cli.Int64SliceFlag{Name: \"intervals\"},\n\t\t\t&cli.IntFlag{Name: \"distance\"},\n\t\t\t&cli.IntSliceFlag{Name: \"times\"},\n\t\t\t&cli.StringFlag{Name: \"dance-move\", Aliases: []string{\"d\"}},\n\t\t\t&cli.StringSliceFlag{Name: \"names\", Aliases: []string{\"N\"}},\n\t\t\t&cli.UintFlag{Name: \"age\"},\n\t\t\t&cli.Uint64Flag{Name: \"bigage\"},\n\t\t},\n\t\tEnableBashCompletion: true,\n\t\tHideHelp:             false,\n\t\tHideHelpCommand:      false,\n\t\tHideVersion:          false,\n\t\tBashComplete: func(cCtx *cli.Context) {\n\t\t\tfmt.Fprintf(cCtx.App.Writer, \"lipstick\\nkiss\\nme\\nlipstick\\nringo\\n\")\n\t\t},\n\t\tBefore: func(cCtx *cli.Context) error {\n\t\t\tfmt.Fprintf(cCtx.App.Writer, \"HEEEERE GOES\\n\")\n\t\t\treturn nil\n\t\t},\n\t\tAfter: func(cCtx *cli.Context) error {\n\t\t\tfmt.Fprintf(cCtx.App.Writer, \"Phew!\\n\")\n\t\t\treturn nil\n\t\t},\n\t\tCommandNotFound: func(cCtx *cli.Context, command string) {\n\t\t\tfmt.Fprintf(cCtx.App.Writer, \"Thar be no %q here.\\n\", command)\n\t\t},\n\t\tOnUsageError: func(cCtx *cli.Context, err error, isSubcommand bool) error {\n\t\t\tif isSubcommand {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Fprintf(cCtx.App.Writer, \"WRONG: %#v\\n\", err)\n\t\t\treturn nil\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tcli.DefaultAppComplete(cCtx)\n\t\t\tcli.HandleExitCoder(errors.New(\"not an exit coder, though\"))\n\t\t\tcli.ShowAppHelp(cCtx)\n\t\t\tcli.ShowCommandCompletions(cCtx, \"nope\")\n\t\t\tcli.ShowCommandHelp(cCtx, \"also-nope\")\n\t\t\tcli.ShowCompletions(cCtx)\n\t\t\tcli.ShowSubcommandHelp(cCtx)\n\t\t\tcli.ShowVersion(cCtx)\n\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.App.Command(\"doo\"))\n\t\t\tif cCtx.Bool(\"infinite\") {\n\t\t\t\tcCtx.App.Run([]string{\"app\", \"doo\", \"wop\"})\n\t\t\t}\n\n\t\t\tif cCtx.Bool(\"forevar\") {\n\t\t\t\tcCtx.App.RunAsSubcommand(cCtx)\n\t\t\t}\n\t\t\tcCtx.App.Setup()\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.App.VisibleCategories())\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.App.VisibleCommands())\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.App.VisibleFlags())\n\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.Args().First())\n\t\t\tif cCtx.Args().Len() > 0 {\n\t\t\t\tfmt.Printf(\"%#v\\n\", cCtx.Args().Get(1))\n\t\t\t}\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.Args().Present())\n\t\t\tfmt.Printf(\"%#v\\n\", cCtx.Args().Tail())\n\n\t\t\tset := flag.NewFlagSet(\"contrive\", 0)\n\t\t\tnc := cli.NewContext(cCtx.App, set, cCtx)\n\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Args())\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Bool(\"nope\"))\n\t\t\tfmt.Printf(\"%#v\\n\", !nc.Bool(\"nerp\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Duration(\"howlong\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Float64(\"hay\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Generic(\"bloop\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Int64(\"bonk\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Int64Slice(\"burnks\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Int(\"bips\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.IntSlice(\"blups\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.String(\"snurt\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.StringSlice(\"snurkles\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Uint(\"flub\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Uint64(\"florb\"))\n\n\t\t\tfmt.Printf(\"%#v\\n\", nc.FlagNames())\n\t\t\tfmt.Printf(\"%#v\\n\", nc.IsSet(\"wat\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Set(\"wat\", \"nope\"))\n\t\t\tfmt.Printf(\"%#v\\n\", nc.NArg())\n\t\t\tfmt.Printf(\"%#v\\n\", nc.NumFlags())\n\t\t\tfmt.Printf(\"%#v\\n\", nc.Lineage()[1])\n\t\t\tnc.Set(\"wat\", \"also-nope\")\n\n\t\t\tec := cli.Exit(\"ohwell\", 86)\n\t\t\tfmt.Fprintf(cCtx.App.Writer, \"%d\", ec.ExitCode())\n\t\t\tfmt.Printf(\"made it!\\n\")\n\t\t\treturn ec\n\t\t},\n\t\tMetadata: map[string]interface{}{\n\t\t\t\"layers\":          \"many\",\n\t\t\t\"explicable\":      false,\n\t\t\t\"whatever-values\": 19.99,\n\t\t},\n\t}\n\n\tif os.Getenv(\"HEXY\") != \"\" {\n\t\tapp.Writer = &hexWriter{}\n\t\tapp.ErrWriter = &hexWriter{}\n\t}\n\n\tapp.Run(os.Args)\n}\n\nfunc wopAction(cCtx *cli.Context) error {\n\tfmt.Fprintf(cCtx.App.Writer, \":wave: over here, eh\\n\")\n\treturn nil\n}\n```\n"
  },
  {
    "path": "docs/v2/examples/generated-help-text.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nThe default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked\nby the cli internals in order to print generated help text for the app, command,\nor subcommand, and break execution.\n\n#### Customization\n\nAll of the help text generation may be customized, and at multiple levels.  The\ntemplates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and\n`SubcommandHelpTemplate` which may be reassigned or augmented, and full override\nis possible by assigning a compatible func to the `cli.HelpPrinter` variable,\ne.g.:\n\n<!-- {\n  \"output\": \"Ha HA.  I pwnd the help!!1\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\t// EXAMPLE: Append to an existing template\n\tcli.AppHelpTemplate = fmt.Sprintf(`%s\n\nWEBSITE: http://awesometown.example.com\n\nSUPPORT: support@awesometown.example.com\n\n`, cli.AppHelpTemplate)\n\n\t// EXAMPLE: Override a template\n\tcli.AppHelpTemplate = `NAME:\n   {{.Name}} - {{.Usage}}\nUSAGE:\n   {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}\n   {{if len .Authors}}\nAUTHOR:\n   {{range .Authors}}{{ . }}{{end}}\n   {{end}}{{if .Commands}}\nCOMMANDS:\n{{range .Commands}}{{if not .HideHelp}}   {{join .Names \", \"}}{{ \"\\t\"}}{{.Usage}}{{ \"\\n\" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}\nGLOBAL OPTIONS:\n   {{range .VisibleFlags}}{{.}}\n   {{end}}{{end}}{{if .Copyright }}\nCOPYRIGHT:\n   {{.Copyright}}\n   {{end}}{{if .Version}}\nVERSION:\n   {{.Version}}\n   {{end}}\n`\n\n\t// EXAMPLE: Replace the `HelpPrinter` func\n\tcli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfmt.Println(\"Ha HA.  I pwnd the help!!1\")\n\t}\n\n\t(&cli.App{}).Run(os.Args)\n}\n```\n\nThe default flag may be customized to something other than `-h/--help` by\nsetting `cli.HelpFlag`, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45halp\"],\n  \"output\": \"haaaaalp.*HALP\"\n} -->\n```go\npackage main\n\nimport (\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tcli.HelpFlag = &cli.BoolFlag{\n\t\tName:    \"haaaaalp\",\n\t\tAliases: []string{\"halp\"},\n\t\tUsage:   \"HALP\",\n\t\tEnvVars: []string{\"SHOW_HALP\", \"HALPPLZ\"},\n\t}\n\n\t(&cli.App{}).Run(os.Args)\n}\n```\n"
  },
  {
    "path": "docs/v2/examples/greet.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nBeing a programmer can be a lonely job. Thankfully by the power of automation\nthat is not the case! Let's create a greeter app to fend off our demons of\nloneliness!\n\nStart by creating a directory named `greet`, and within it, add a file,\n`greet.go` with the following code in it:\n\n<!-- {\n  \"output\": \"Hello friend!\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tName:  \"greet\",\n\t\tUsage: \"fight the loneliness!\",\n\t\tAction: func(*cli.Context) error {\n\t\t\tfmt.Println(\"Hello friend!\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nInstall our command to the `$GOPATH/bin` directory:\n\n```sh-session\n$ go install\n```\n\nFinally run our new command:\n\n```sh-session\n$ greet\nHello friend!\n```\n\ncli also generates neat help text:\n\n```sh-session\n$ greet help\nNAME:\n    greet - fight the loneliness!\n\nUSAGE:\n    greet [global options] command [command options] [arguments...]\n\nCOMMANDS:\n    help, h  Shows a list of commands or help for one command\n\nGLOBAL OPTIONS\n    --help, -h  show help (default: false)\n```\n"
  },
  {
    "path": "docs/v2/examples/subcommands-categories.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nFor additional organization in apps that have many subcommands, you can\nassociate a category for each command to group them together in the help\noutput, e.g.:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName: \"noop\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"add\",\n\t\t\t\tCategory: \"template\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"remove\",\n\t\t\t\tCategory: \"template\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill include:\n\n```\nCOMMANDS:\n  noop\n\n  Template actions:\n    add\n    remove\n```\n"
  },
  {
    "path": "docs/v2/examples/subcommands.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nSubcommands can be defined for a more git-like command line app.\n\n<!-- {\n  \"args\": [\"template\", \"add\"],\n  \"output\": \"new task template: .+\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Println(\"added task: \", cCtx.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cCtx.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"template\",\n\t\t\t\tAliases: []string{\"t\"},\n\t\t\t\tUsage:   \"options for task templates\",\n\t\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"add\",\n\t\t\t\t\t\tUsage: \"add a new template\",\n\t\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t\tfmt.Println(\"new task template: \", cCtx.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"remove\",\n\t\t\t\t\t\tUsage: \"remove an existing template\",\n\t\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t\tfmt.Println(\"removed task template: \", cCtx.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v2/examples/suggestions.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nTo enable flag and command suggestions, set `app.Suggest = true`. If the suggest\nfeature is enabled, then the help output of the corresponding command will\nprovide an appropriate suggestion for the provided flag or subcommand if\navailable.\n"
  },
  {
    "path": "docs/v2/examples/timestamp-flag.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nUsing the timestamp flag is simple. Please refer to\n[`time.Parse`](https://golang.org/pkg/time/#example_Parse) to get possible\nformats.\n\n<!-- {\n  \"args\": [\"&#45;&#45;meeting\", \"2019-08-12T15:04:05\"],\n  \"output\": \"2019\\\\-08\\\\-12 15\\\\:04\\\\:05 \\\\+0000 UTC\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.TimestampFlag{Name: \"meeting\", Layout: \"2006-01-02T15:04:05\"},\n\t\t},\n\t\tAction: func(cCtx *cli.Context) error {\n\t\t\tfmt.Printf(\"%s\", cCtx.Timestamp(\"meeting\").String())\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIn this example the flag could be used like this:\n\n```sh-session\n$ myapp --meeting 2019-08-12T15:04:05\n```\n\nWhen the layout doesn't contain timezones, timestamp will render with UTC. To\nchange behavior, a default timezone can be provided with flag definition:\n\n```go\napp := &cli.App{\n\tFlags: []cli.Flag{\n\t\t&cli.TimestampFlag{Name: \"meeting\", Layout: \"2006-01-02T15:04:05\", Timezone: time.Local},\n\t},\n}\n```\n\n(time.Local contains the system's local time zone.)\n\nSide note: quotes may be necessary around the date depending on your layout (if\nyou have spaces for instance)\n"
  },
  {
    "path": "docs/v2/examples/version-flag.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nThe default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which\nis checked by the cli internals in order to print the `App.Version` via\n`cli.VersionPrinter` and break execution.\n\n#### Customization\n\nThe default flag may be customized to something other than `-v/--version` by\nsetting `cli.VersionFlag`, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45print-version\"],\n  \"output\": \"partay version v19\\\\.99\\\\.0\"\n} -->\n```go\npackage main\n\nimport (\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tcli.VersionFlag = &cli.BoolFlag{\n\t\tName:    \"print-version\",\n\t\tAliases: []string{\"V\"},\n\t\tUsage:   \"print only the version\",\n\t}\n\n\tapp := &cli.App{\n\t\tName:    \"partay\",\n\t\tVersion: \"v19.99.0\",\n\t}\n\tapp.Run(os.Args)\n}\n```\n\nAlternatively, the version printer at `cli.VersionPrinter` may be overridden,\ne.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45version\"],\n  \"output\": \"version=v19\\\\.99\\\\.0 revision=fafafaf\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nvar (\n\tRevision = \"fafafaf\"\n)\n\nfunc main() {\n\tcli.VersionPrinter = func(cCtx *cli.Context) {\n\t\tfmt.Printf(\"version=%s revision=%s\\n\", cCtx.App.Version, Revision)\n\t}\n\n\tapp := &cli.App{\n\t\tName:    \"partay\",\n\t\tVersion: \"v19.99.0\",\n\t}\n\tapp.Run(os.Args)\n}\n```\n"
  },
  {
    "path": "docs/v2/getting-started.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nOne of the philosophies behind cli is that an API should be playful and full of\ndiscovery. So a cli app can be as little as one line of code in `main()`.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"A new cli application\"\n} -->\n```go\npackage main\n\nimport (\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\t(&cli.App{}).Run(os.Args)\n}\n```\n\nThis app will run and show help text, but is not very useful.\n\n```\n$ wl-paste > hello.go\n$ go build hello.go\n$ ./hello\nNAME:\n   hello - A new cli application\n\nUSAGE:\n   hello [global options] command [command options] [arguments...]\n\nCOMMANDS:\n   help, h  Shows a list of commands or help for one command\n\nGLOBAL OPTIONS:\n   --help, -h  show help (default: false)\n```\n\nLet's add an action to execute and some help documentation:\n\n<!-- {\n  \"output\": \"boom! I say!\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc main() {\n\tapp := &cli.App{\n\t\tName:  \"boom\",\n\t\tUsage: \"make an explosive entrance\",\n\t\tAction: func(*cli.Context) error {\n\t\t\tfmt.Println(\"boom! I say!\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := app.Run(os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nRunning this already gives you a ton of functionality, plus support for things\nlike subcommands and flags, which are covered below.\n"
  },
  {
    "path": "docs/v2/migrating-from-older-releases.md",
    "content": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nThere are a small set of breaking changes between v1 and v2.  Converting is\nrelatively straightforward and typically takes less than an hour. Specific steps\nare included in [Migration Guide: v1 to v2](../migrate-v1-to-v2.md). Also see\nthe [pkg.go.dev docs](https://pkg.go.dev/github.com/urfave/cli/v2) for v2 API\ndocumentation.\n"
  },
  {
    "path": "docs/v2/migrating-to-v3.md",
    "content": "---\ntags:\n  - v2\n---\n\nThere are a small set of breaking changes between v2 and v3.\nConverting is relatively straightforward and typically takes less than\nan hour. Specific steps are included in\n[Migration Guide: v2 to v3](../migrate-v2-to-v3.md).\n"
  },
  {
    "path": "docs/v3/examples/arguments/advanced.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThe [Basics] showed how to access arguments for a command. They are all retrieved as strings which is fine\nbut it we need to say get integers or timestamps the user would have to convert from string to desired type. \nTo ease the burden on users the `cli` library offers predefined `{Type}Arg` and `{Type}Args` structure to faciliate this.\nThe value of the argument can be retrieved using the `command.{Type}Arg()` function. For e.g\n\n<!-- {\n  \"args\" : [\"10\"],\n  \"output\": \"We got 10\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tArguments: []cli.Argument{\n\t\t\t&cli.IntArg{\n\t\t\t\tName: \"someint\",\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"We got %d\", cmd.IntArg(\"someint\"))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nRunning this program with an argument gives the following output\n\n```sh-session\n$ greet 10\nWe got 10\n```\n\nInstead of using the `cmd.{Type}Arg()` function to retrieve the argument value a destination for the argument can be set\nfor e.g\n\n<!-- {\n  \"args\" : [\"25\"],\n  \"output\": \"We got 25\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tvar ival int\n\tcmd := &cli.Command{\n\t\tArguments: []cli.Argument{\n\t\t\t&cli.IntArg{\n\t\t\t\tName: \"someint\",\n\t\t\t\tDestination: &ival,\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"We got %d\", ival)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nSome of the basic types arguments suported are\n\n- `FloatArg`\n- `IntArg`\n- `Int8Arg`\n- `Int16Arg`\n- `Int32Arg`\n- `Int64Arg`\n- `StringArg`\n- `UintArg`\n- `Uint8Arg`\n- `Uint16Arg`\n- `Uint32Arg`\n- `Uint64Arg`\n- `TimestampArg`\n\nThis is ok for single value arguments. Any number of these single value arguments can be concatenated in the `Arguments`\nslice field of `Command`. \n\nThe library also support multi value arguments for e.g\n\n<!-- {\n  \"args\" : [\"10\", \"20\"],\n  \"output\": \"We got &#91;10 20&#93;\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tArguments: []cli.Argument{\n\t\t\t&cli.IntArgs{\n\t\t\t\tName: \"someint\",\n\t\t\t\tMin: 0,\n\t\t\t\tMax: -1,\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Println(\"We got \", cmd.IntArgs(\"someint\"))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nSome things to note about multi value arguments\n\n1. They are of `{Type}Args` type rather than `{Type}Arg` to differentiate them from single value arguments.\n2. The `Max` field needs to be defined to a non zero value without which it cannot be parsed.\n3. `Max` field value needs to be greater than the `Min` field value.\n\nAs with single value args the destination field can be set\n\n<!-- {\n  \"args\" : [\"10\", \"30\"],\n  \"output\": \"We got &#91;10 30&#93;\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tvar ivals []int\n\tcmd := &cli.Command{\n\t\tArguments: []cli.Argument{\n\t\t\t&cli.IntArgs{\n\t\t\t\tName: \"someint\",\n\t\t\t\tMin: 0,\n\t\t\t\tMax: -1,\n\t\t\t\tDestination: &ivals,\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Println(\"We got \", ivals)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nFollowing multi value arguments are supported\n\n- `FloatArgs`\n- `IntArgs`\n- `Int8Args`\n- `Int16Args`\n- `Int32Args`\n- `Int64Args`\n- `StringArgs`\n- `UintArgs`\n- `Uint8Args`\n- `Uint16Args`\n- `Uint32Args`\n- `Uint64Args`\n- `TimestampArgs`\n\nIt goes without saying that the chain of arguments set in the Arguments slice need to be consistent. Generally a glob\nargument(`max=-1`) should be set for the argument at the end of the slice. To glob args we arent interested in we coud add\nthe following to the end of the Arguments slice and retrieve them as a slice\n\n```\n&StringArgs{\n\tMax: -1,\n},\n```\n"
  },
  {
    "path": "docs/v3/examples/arguments/basics.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nLets add some arguments to our greeter app. This allows you to change the behaviour of\nthe app depending on what argument has been passed. You can lookup arguments by calling \nthe `Args` function on `cli.Command`, e.g.:\n\n<!-- {\n  \"args\" : [\"Friend\"],\n  \"output\": \"Hello \\\"Friend\\\"\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"Hello %q\", cmd.Args().Get(0))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nRunning this program with an argument gives the following output\n\n```sh-session\n$ greet friend\nHello \"Friend\"\n```\n\nAny number of arguments can be passed to the greeter app. We can get the number of arguments\nand each argument using the `Args`\n\n<!-- {\n  \"args\" : [\"Friend\", \"1\", \"bar\", \"2.0\"],\n  \"output\": \"Number of args : 4\\nHello Friend 1 bar 2.0\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"Number of args : %d\\n\", cmd.Args().Len())\n\t\t\tvar out string\n\t\t\tfor i := 0; i < cmd.Args().Len(); i++ {\n\t\t\t\tout = out + fmt.Sprintf(\" %v\", cmd.Args().Get(i))\n\t\t\t}\n\t\t\tfmt.Printf(\"Hello%v\", out)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nRunning this program with an argument gives the following output\n\n```sh-session\n$ greet Friend 1 bar 2.0\nNumber of args : 4\nHello Friend 1 bar 2.0\n```\n"
  },
  {
    "path": "docs/v3/examples/completions/customizations.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nIf default completion isn't sufficient additional customizations are available \n\n- custom auto-completion\n- customizing completion command\n\n#### Custom auto-completion\n<!-- {\n  \"args\": [\"complete\", \"&#45;&#45;generate&#45;shell&#45;completion\"],\n  \"output\": \"laundry\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\ttasks := []string{\"cook\", \"clean\", \"laundry\", \"eat\", \"sleep\", \"code\"}\n\n\tcmd := &cli.Command{\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tShellComplete: func(ctx context.Context, cmd *cli.Command) {\n\t\t\t\t\t// This will complete if no args are passed\n\t\t\t\t\tif cmd.NArg() > 0 {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tfor _, t := range tasks {\n\t\t\t\t\t\tfmt.Println(t)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n![](../../images/custom-bash-autocomplete.gif)\n\n#### Customize a completion command\n\nBy default, a completion command is hidden, meaning the command isn't included in the help message.\nYou can customize it by setting root Command's `ConfigureShellCompletionCommand`.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tName: \"greet\",\n\t\t// EnableShellCompletion is unnecessary\n\t\tConfigureShellCompletionCommand: func(cmd *cli.Command) { // cmd is a completion command\n\t\t\tcmd.Hidden = false // Make a completion command public\n\t\t\tcmd.Usage = \"...\" // Customize Usage\n\t\t\tcmd.Description = \"...\" // Customize Description\n\t\t},\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:  \"hello\",\n\t\t\t\tUsage: \"Say hello\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"Hello\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n#### Customization\n\nThe default shell completion flag (`--generate-shell-completion`) is defined as\n`cli.EnableShellCompletion`, and may be redefined if desired, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45;generate&#45;shell&#45;completion\"],\n  \"output\": \"wat\\nhelp\\n\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName: \"wat\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/completions/shell-completions.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThe urfave/cli v3 library supports programmable completion for apps utilizing its framework. This means\nthat the completion is generated dynamically at runtime by invokiong the app itself with a special hidden\nflag. The urfave/cli searches for this flag and activates a different flow for command paths than regular flow\nThe following shells are supported\n\n - bash\n - zsh\n - fish\n - powershell\n\nEnabling auto complete requires 2 things\n\n - Setting the `EnableShellCompletion` field on root `Command` object to `true`. \n - Sourcing the completion script for that particular shell. \n\nThe completion script for a particular shell can be retrieved by running the \"completion\" subcommand\non the app after the `EnableShellCompletion` field on root `Command` object has been set to `true`. \n\nConsider the following program\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tName: \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"added task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"template\",\n\t\t\t\tAliases: []string{\"t\"},\n\t\t\t\tUsage:   \"options for task templates\",\n\t\t\t\tCommands: []*cli.Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"add\",\n\t\t\t\t\t\tUsage: \"add a new template\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"new task template: \", cmd.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"remove\",\n\t\t\t\t\t\tUsage: \"remove an existing template\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"removed task template: \", cmd.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nAfter compiling this app as `greet` we can generate the autocompletion as following\nin bash script\n\n```sh-session\n$ greet completion bash\n```\n\nThis file can be saved to /etc/bash_completion.d/greet or $HOME/.bash_completion.d/greet\nwhere it will be automatically picked in new bash shells. For the current shell these\ncan be sourced either using filename or from generation command directly\n\n```sh-session\n$ source ~/.bash_completion.d/greet\n```\n\n```sh-session\n$ source <(greet completion bash)\n```\n\nThe procedure for other shells is similar to bash though the specific paths for each of the \nshells may vary. Some of the sections below detail the setup need for other shells as\nwell as examples in those shells.\n\n#### Default auto-completion\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"added task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"template\",\n\t\t\t\tAliases: []string{\"t\"},\n\t\t\t\tUsage:   \"options for task templates\",\n\t\t\t\tCommands: []*cli.Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"add\",\n\t\t\t\t\t\tUsage: \"add a new template\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"new task template: \", cmd.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"remove\",\n\t\t\t\t\t\tUsage: \"remove an existing template\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"removed task template: \", cmd.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n![](../../images/default-bash-autocomplete.gif)\n\n#### ZSH Support\n\nAdding the following lines to\nyour ZSH configuration file (usually `.zshrc`) will allow the auto-completion to\npersist across new shells:\n\n```sh-session\n$ PROG=<myprogram>\n$ source path/to/autocomplete/zsh_autocomplete\n```\n\n#### ZSH default auto-complete example\n![](../../images/default-zsh-autocomplete.gif)\n\n#### PowerShell Support\n\nGenerate the completion script as save it to `<my program>.ps1` . This file can be moved to \nanywhere in your file system.  The location of script does not matter, only the file name of the\nscript has to match the your program's binary name.\n\nTo activate it, enter:\n\n```powershell\n& path/to/autocomplete/<my program>.ps1\n```\n\nTo persist across new shells, open the PowerShell profile (with `code $profile`\nor `notepad $profile`) and add the line:\n\n```powershell\n& path/to/autocomplete/<my program>.ps1\n```\n"
  },
  {
    "path": "docs/v3/examples/exit-codes.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nCalling `Command.Run` will not automatically call `os.Exit`, which means that by\ndefault the exit code will \"fall through\" to being `0`.  An explicit exit code\nmay be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a\n`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:\n\n<!-- {\n  \"error\": \"Ginger croutons are not in the soup\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{\n\t\t\t\tName:  \"ginger-crouton\",\n\t\t\t\tUsage: \"is it in the soup?\",\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tif !cmd.Bool(\"ginger-crouton\") {\n\t\t\t\treturn cli.Exit(\"Ginger croutons are not in the soup\", 86)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/flags/advanced.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\n#### Alternate Names\n\nYou can set alternate (or short) names for flags by providing a list of strings for `Aliases`\ne.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;lang string, &#45;l string.*language for the greeting.*default: \\\"english\\\"\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"language for the greeting\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nThat flag can then be set with `--lang spanish` or `-l spanish`. Note that\ngiving two different forms of the same flag in the same command invocation is an\nerror.\n\n#### Multiple Values per Single Flag\n\nAs noted in the basics for flag, the simple flags allow only one value per flag and only the last\nentered value on command line will be returned to user on query. \n\n`urfave/cli` also supports multi-value flags called slice flags. These flags can take multiple values of same type. \nIn addition they can be invoked multiple times on the command line and values will be appended to original value\nof the flag and returned to the user as a slice\n\n- `IntSliceFlag`\n- `Int8SliceFlag`\n- `Int16SliceFlag`\n- `Int32SliceFlag`\n- `Int64SliceFlag`\n- `UintSliceFlag`\n- `Uint8SliceFlag`\n- `Uint16SliceFlag`\n- `Uint32SliceFlag`\n- `Uint64SliceFlag`\n- `StringSliceFlag`\n- `FloatSliceFlag`\n\n<!-- {\n  \"args\": [\"&#45;&#45;greeting\", \"Hello\", \"&#45;&#45;greeting\", \"Hola\"],\n  \"output\": \"Hello, Hola\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringSliceFlag{\n\t\t\t\tName:  \"greeting\",\n\t\t\t\tUsage: \"Pass multiple greetings\",\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Println(strings.Join(cmd.StringSlice(\"greeting\"), `, `))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nMultiple values need to be passed as separate, repeating flags, e.g. `--greeting Hello --greeting Hola`.\n\n#### Count for bool flag\n\nFor bool flags you can specify the flag multiple times to get a count(e.g -v -v -v or -vvv)\n\n> If you want to support the `-vvv` flag, you need to set `Command.UseShortOptionHandling`.\n\n<!-- {\n  \"args\": [\"&#45;&#45;foo\", \"&#45;&#45;foo\", \"&#45;fff\"],\n  \"output\": \"count 5\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tvar count int\n\n\tcmd := &cli.Command{\n\t\tUseShortOptionHandling: true,\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{\n\t\t\t\tName:        \"foo\",\n\t\t\t\tUsage:       \"foo greeting\",\n\t\t\t\tAliases:     []string{\"f\"},\n\t\t\t\tConfig: cli.BoolConfig{\n\t\t\t\t\tCount: &count,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Println(\"count\", count)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n#### Placeholder Values\n\nSometimes it's useful to specify a flag's value within the usage string itself.\nSuch placeholders are indicated with back quotes.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;config FILE, &#45;c FILE\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"config\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"Load configuration from `FILE`\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\n--config FILE, -c FILE   Load configuration from FILE\n```\n\nNote that only the first placeholder is used. Subsequent back-quoted words will\nbe left as-is.\n\n\n#### Ordering\n\nFlags for the application and commands are shown in the order they are defined.\nHowever, it's possible to sort them from outside this library by using `FlagsByName`\nor `CommandsByName` with `sort`.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \".*Load configuration from FILE\\n.*Language for the greeting.*\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"Language for the greeting\",\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"config\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"Load configuration from `FILE`\",\n\t\t\t},\n\t\t},\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tsort.Sort(cli.FlagsByName(cmd.Flags))\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\n--config FILE, -c FILE  Load configuration from FILE\n--lang value, -l value  Language for the greeting (default: \"english\")\n```\n\n#### Required Flags\n\nYou can mark a flag as *required* by setting the `Required` field to `true`. If a user\ndoes not provide a required flag, they will be shown an error message.\n\nTake for example this app that requires the `lang` flag:\n\n<!-- {\n  \"error\": \"Required flag \\\"lang\\\" not set\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:     \"lang\",\n\t\t\t\tValue:    \"english\",\n\t\t\t\tUsage:    \"language for the greeting\",\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\toutput := \"Hello\"\n\t\t\tif cmd.String(\"lang\") == \"spanish\" {\n\t\t\t\toutput = \"Hola\"\n\t\t\t}\n\t\t\tfmt.Println(output)\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIf the command is run without the `lang` flag, the user will see the following message\n\n```\nRequired flag \"lang\" not set\n```\n\n#### Flag Groups\n\nYou can make groups of flags that are mutually exclusive of each other.\nThis provides the ability to provide configuration options out of which\nonly one can be defined on the command line.\n\nTake for example this app that looks up a user using one of multiple options:\n\n<!-- {\n  \"error\": \"one of these flags needs to be provided: login, id\"\n} -->\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tName: \"authors\",\n\t\tMutuallyExclusiveFlags: []cli.MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tRequired: true,\n\t\t\t\tFlags: [][]cli.Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\t\tName:  \"login\",\n\t\t\t\t\t\t\tUsage: \"the username of the user\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\t\tName:  \"id\",\n\t\t\t\t\t\t\tUsage: \"the user id (defaults to 'me' for current user)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tu, err := getUser(ctx, cmd)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdata, err := json.Marshal(u)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Println(string(data))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\ntype User struct {\n\tId        string `json:\"id\"`\n\tLogin     string `json:\"login\"`\n\tFirstName string `json:\"firstName\"`\n\tLastName  string `json:\"lastName\"`\n}\n\n// Mock function that returns a static user value.\n// Would retrieve a user from an API or database with other functions.\nfunc getUser(ctx context.Context, cmd *cli.Command) (User, error) {\n\tu := User{\n\t\tId:        \"abc123\",\n\t\tLogin:     \"vwoolf@example.com\",\n\t\tFirstName: \"Virginia\",\n\t\tLastName:  \"Woolf\",\n\t}\n\tif login := cmd.String(\"login\"); login != \"\" {\n\t\tfmt.Printf(\"Getting user by login: %s\\n\", login)\n\t\tu.Login = login\n\t}\n\tif id := cmd.String(\"id\"); id != \"\" {\n\t\tfmt.Printf(\"Getting user by id: %s\\n\", id)\n\t\tu.Id = id\n\t}\n\treturn u, nil\n}\n```\n\nIf the command is run without either the `login` or `id` flag, the user will\nsee the following message\n\n```\none of these flags needs to be provided: login, id\n```\n\n\n#### Default Values for help output\n\nSometimes it's useful to specify a flag's default help-text value within the\nflag declaration. This can be useful if the default value for a flag is a\ncomputed value. The default value can be set via the `DefaultText` struct field.\n\nFor example this:\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"&#45;&#45;port int\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.IntFlag{\n\t\t\t\tName:        \"port\",\n\t\t\t\tUsage:       \"Use a randomized port\",\n\t\t\t\tValue:       0,\n\t\t\t\tDefaultText: \"random\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\n--port value  Use a randomized port (default: random)\n```\n\n#### Flag Actions\n\nHandlers can be registered per flag which are triggered after a flag has been processed. \nThis can be used for a variety of purposes, one of which is flag validation\n\n<!-- {\n  \"args\": [\"&#45;&#45;port\",\"70000\"],\n  \"error\": \"Flag port value 70000 out of range[0-65535]\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.IntFlag{\n\t\t\t\tName:        \"port\",\n\t\t\t\tUsage:       \"Use a randomized port\",\n\t\t\t\tValue:       0,\n\t\t\t\tDefaultText: \"random\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command, v int) error {\n\t\t\t\t\tif v >= 65536 {\n\t\t\t\t\t\treturn fmt.Errorf(\"Flag port value %v out of range[0-65535]\", v)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill result in help output like:\n\n```\nFlag port value 70000 out of range[0-65535]\n```\n"
  },
  {
    "path": "docs/v3/examples/flags/basics.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nFlags, also called options, can be used to control various behaviour of the app\nby turning on/off capabilities or setting some configuration and so on. \nSetting and querying flags is done using the ```cmd.<FlagType>(<flagName>)```\nfunction\n\nHere is an example of using a StringFlag which accepts a string as its option value\n\n<!-- {\n  \"output\": \"Hello Nefertiti\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:  \"lang\",\n\t\t\t\tValue: \"english\",\n\t\t\t\tUsage: \"language for the greeting\",\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tname := \"Nefertiti\"\n\t\t\tif cmd.NArg() > 0 {\n\t\t\t\tname = cmd.Args().Get(0)\n\t\t\t}\n\t\t\tif cmd.String(\"lang\") == \"spanish\" {\n\t\t\t\tfmt.Println(\"Hola\", name)\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Hello\", name)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nThis very simple program gives a lot of outputs depending on the value of the flag set.\n```sh-session\n$ greet\nHello Nefertiti\n```\nNote that the Value for the flag is the default value that will be used when the flag\nis not set on the command line. Since in the above invocation no flag was specified the\nvalue of the \"lang\" flag was default to \"english\". Now lets change the language\n\n```sh-session\n$ greet --lang spanish\nHola Nefertiti\n```\n\nFlag values can be provided with a space after the flag name or using the ```=``` sign\n```sh-session\n$ greet --lang=spanish\nHola Nefertiti\n$ greet --lang=spanish my-friend\nHola my-friend\n```\n\nWhile the value of any flag can be retrieved using ```command.<flagType>``` sometimes\nit is convenient to have the value of the flag automatically stored in a destination\nvariable for a flag. If the `Value` is set for the flag, it will be shown as default,\nand destination will be set to this value before parsing flag on the command line.\n\n<!-- {\n  \"output\": \"Hello someone\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tvar language string\n\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:        \"lang\",\n\t\t\t\tValue:       \"english\",\n\t\t\t\tUsage:       \"language for the greeting\",\n\t\t\t\tDestination: &language,\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tname := \"someone\"\n\t\t\tif cmd.NArg() > 0 {\n\t\t\t\tname = cmd.Args().Get(0)\n\t\t\t}\n\t\t\tif language == \"spanish\" {\n\t\t\t\tfmt.Println(\"Hola\", name)\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"Hello\", name)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nNote that most flag can be invoked multiple times but only the last value entered for the flag\nwill be provided to the user(with some exceptions. See flags-advanced.md)\n\nThe following basic flags are supported\n\n- `IntFlag`\n- `Int8Flag`\n- `Int16Flag`\n- `Int32Flag`\n- `Int64Flag`\n- `UintFlag`\n- `Uint8Flag`\n- `Uint16Flag`\n- `Uint32Flag`\n- `Uint64Flag`\n- `BoolFlag`\n- `DurationFlag`\n- `FloatFlag`\n- `Float32Flag`\n- `Float64Flag`\n- `StringFlag`\n- `TimestampFlag`\n\nFor full list of flags see [`https://pkg.go.dev/github.com/urfave/cli/v3`](https://pkg.go.dev/github.com/urfave/cli/v3)\n\n### Timestamp Flag ###\n\nUsing the timestamp flag is similar to other flags but special attention is need \nfor the format to be provided to the flag . Please refer to\n[`time.Parse`](https://golang.org/pkg/time/#example_Parse) to get possible\nformats.\n\n<!-- {\n  \"args\": [\"&#45;&#45;meeting\", \"2019-08-12T15:04:05\"],\n  \"output\": \"2019\\\\-08\\\\-12 15\\\\:04\\\\:05 \\\\+0000 UTC\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.TimestampFlag{\n\t\t\t\tName: \"meeting\", \n\t\t\t\tConfig: cli.TimestampConfig{\n\t\t\t\t\tLayouts: []string{\"2006-01-02T15:04:05\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"%s\", cmd.Timestamp(\"meeting\").String())\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIn this example the flag could be used like this:\n\n```sh-session\n$ myapp --meeting 2019-08-12T15:04:05\n```\n\nWhen the layout doesn't contain timezones, timestamp will render with UTC. To\nchange behavior, a default timezone can be provided with flag definition:\n\n```go\ncmd := &cli.Command{\n\tFlags: []cli.Flag{\n\t\t&cli.TimestampFlag{\n\t\t\tName: \"meeting\",\n\t\t\tConfig: cli.TimestampConfig{\n\t\t\t\tTimezone: time.Local,\n\t\t\t\tAvailableLayouts: []string{\"2006-01-02T15:04:05\"},\n\t\t\t},\n\t\t},\n\t},\n}\n```\n\n(time.Local contains the system's local time zone.)\n\nSide note: quotes may be necessary around the date depending on your layout (if\nyou have spaces for instance)\n\n### Version Flags ###\n\nA default version flag (`-v/--version`) is provided as `cli.VersionFlag`, which\nis checked by the cli internals in order to print the `Command.Version` via\n`cli.VersionPrinter` and break execution.\n\n#### Customization\n\nThe default flag may be customized to something other than `-v/--version` by\nsetting fields of `cli.VersionFlag`, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45print-version\"],\n  \"output\": \"partay version v19\\\\.99\\\\.0\"\n} -->\n```go\npackage main\n\nimport (\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcli.VersionFlag = &cli.BoolFlag{\n\t\tName:    \"print-version\",\n\t\tAliases: []string{\"V\"},\n\t\tUsage:   \"print only the version\",\n\t}\n\n\tcmd := &cli.Command{\n\t\tName:    \"partay\",\n\t\tVersion: \"v19.99.0\",\n\t}\n\tcmd.Run(context.Background(), os.Args)\n}\n```\n\nAlternatively, the version printer at `cli.VersionPrinter` may be overridden,\ne.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45version\"],\n  \"output\": \"version=v19\\\\.99\\\\.0 revision=fafafaf\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nvar (\n\tRevision = \"fafafaf\"\n)\n\nfunc main() {\n\tcli.VersionPrinter = func(cmd *cli.Command) {\n\t\tfmt.Printf(\"version=%s revision=%s\\n\", cmd.Root().Version, Revision)\n\t}\n\n\tcmd := &cli.Command{\n\t\tName:    \"partay\",\n\t\tVersion: \"v19.99.0\",\n\t}\n\tcmd.Run(context.Background(), os.Args)\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/flags/short-options.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nTraditional use of options using their shortnames look like this:\n\n```sh-session\n$ cmd -s -o -m \"Some message\"\n```\n\nSuppose you want users to be able to combine options with their shortnames. This\ncan be done using the `UseShortOptionHandling` bool in your app configuration,\nor for individual commands by attaching it to the command configuration. For\nexample:\n\n<!-- {\n  \"args\": [\"short\", \"&#45;som\", \"Some message\"],\n  \"output\": \"serve: true\\noption: true\\nmessage: Some message\\n\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tUseShortOptionHandling: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:  \"short\",\n\t\t\t\tUsage: \"complete a task on the list\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t\t\t\t&cli.BoolFlag{Name: \"option\", Aliases: []string{\"o\"}},\n\t\t\t\t\t&cli.StringFlag{Name: \"message\", Aliases: []string{\"m\"}},\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"serve:\", cmd.Bool(\"serve\"))\n\t\t\t\t\tfmt.Println(\"option:\", cmd.Bool(\"option\"))\n\t\t\t\t\tfmt.Println(\"message:\", cmd.String(\"message\"))\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIf your program has any number of bool flags such as `serve` and `option`, and\noptionally one non-bool flag `message`, with the short options of `-s`, `-o`,\nand `-m` respectively, setting `UseShortOptionHandling` will also support the\nfollowing syntax:\n\n```sh-session\n$ cmd -som \"Some message\"\n```\n\nIf you enable `UseShortOptionHandling`, then you must not use any flags that\nhave a single leading `-` or this will result in failures. For example,\n`-option` can no longer be used. Flags with two leading dashes (such as\n`--options`) are still valid.\n"
  },
  {
    "path": "docs/v3/examples/flags/value-sources.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nFlags can have their default values set from different sources. The following sources are\nprovided by default with `urfave/cli`\n\n - Environment\n - Text Files\n\nThe library also provides a framework for users to plugin their own implementation of value sources\nto be fetched via other mechanisms(http and so on). \n\nIn addition there is a `urfave/cli-altsrc` repo which hosts some common value sources to read \nfrom files or via http/https. \n\n - YAML\n - JSON\n - TOML\n\n#### Values from the Environment\n\nTo set a value from the environment use `cli.EnvVars`.  e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"language for the greeting.*APP_LANG\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"language for the greeting\",\n\t\t\t\tSources: cli.EnvVars(\"APP_LANG\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nIf `cli.EnvVars` contains more than one string, the first environment variable that\nresolves is used.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"lang\",\n\t\t\t\tAliases: []string{\"l\"},\n\t\t\t\tValue:   \"english\",\n\t\t\t\tUsage:   \"language for the greeting\",\n\t\t\t\tSources: cli.EnvVars(\"LEGACY_COMPAT_LANG\", \"APP_LANG\", \"LANG\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n#### Values from files\n\nYou can also have the default value set from file via `cli.File`.  e.g.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"password for the mysql database\"\n} -->\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:     \"password\",\n\t\t\t\tAliases:  []string{\"p\"},\n\t\t\t\tUsage:    \"password for the mysql database\",\n\t\t\t\tSources: cli.Files(\"/etc/mysql/password\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nNote that default values are set in the same order as they are defined in the\n`Sources` param. This allows the user to choose order of priority\n\n#### Values from alternate input sources (YAML, TOML, and others)\n\nThere is a separate package [altsrc](https://github.com/urfave/cli-altsrc) that adds support for getting flag values\nfrom other file input sources.\n\nCurrently supported input source formats by that library are:\n\n- YAML\n- JSON\n- TOML\n\nA simple straight forward usage would be\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n\t\"github.com/urfave/cli-altsrc/v3\"\n\tyaml \"github.com/urfave/cli-altsrc/v3/yaml\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"password\",\n\t\t\t\tAliases: []string{\"p\"},\n\t\t\t\tUsage:   \"password for the mysql database\",\n\t\t\t\tSources: cli.NewValueSourceChain(yaml.YAML(\"somekey\", altsrc.StringSourcer(\"/path/to/filename\"))),\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nSometime the source name is itself provided by another CLI flag. To allow the library to \"lazy-load\"\nthe file when needed we use the `altsrc.NewStringPtrSourcer` function to bind the value of the flag \nto a pointer that is set as a destination of another flag\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n\t\"github.com/urfave/cli-altsrc/v3\"\n\tyaml \"github.com/urfave/cli-altsrc/v3/yaml\"\n)\n\nfunc main() {\n\tvar filename string\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:        \"file\",\n\t\t\t\tAliases:     []string{\"f\"},\n\t\t\t\tValue:       \"/path/to/default\",\n\t\t\t\tUsage:       \"filename for mysql database\",\n\t\t\t\tDestination: &filename,\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"password\",\n\t\t\t\tAliases: []string{\"p\"},\n\t\t\t\tUsage:   \"password for the mysql database\",\n\t\t\t\tSources: cli.NewValueSourceChain(yaml.YAML(\"somekey\", altsrc.NewStringPtrSourcer(&filename))),\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/full-api-example.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\n**Notice**: This is a contrived (functioning) example meant strictly for API\ndemonstration purposes. Use of one's imagination is encouraged.\n\n<!-- {\n  \"output\": \"made it!\\nPhew!\"\n} -->\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n\t\"slices\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc init() {\n\tcli.RootCommandHelpTemplate += \"\\nCUSTOMIZED: you bet ur muffins\\n\"\n\tcli.CommandHelpTemplate += \"\\nYMMV\\n\"\n\tcli.SubcommandHelpTemplate += \"\\nor something\\n\"\n\n\tcli.HelpFlag = &cli.BoolFlag{Name: \"halp\"}\n\tcli.VersionFlag = &cli.BoolFlag{Name: \"print-version\", Aliases: []string{\"V\"}}\n\n\tcli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfmt.Fprintf(w, \"best of luck to you\\n\")\n\t}\n\tcli.VersionPrinter = func(cmd *cli.Command) {\n\t\tfmt.Fprintf(cmd.Root().Writer, \"version=%s\\n\", cmd.Root().Version)\n\t}\n\tcli.OsExiter = func(cmd int) {\n\t\tfmt.Fprintf(cli.ErrWriter, \"refusing to exit %d\\n\", cmd)\n\t}\n\tcli.ErrWriter = ioutil.Discard\n\tcli.FlagStringer = func(fl cli.Flag) string {\n\t\treturn fmt.Sprintf(\"\\t\\t%s\", fl.Names()[0])\n\t}\n}\n\ntype hexWriter struct{}\n\nfunc (w *hexWriter) Write(p []byte) (int, error) {\n\tfor _, b := range p {\n\t\tfmt.Printf(\"%x\", b)\n\t}\n\tfmt.Printf(\"\\n\")\n\n\treturn len(p), nil\n}\n\ntype genericType struct {\n\ts string\n}\n\nfunc (g *genericType) Set(value string) error {\n\tg.s = value\n\treturn nil\n}\n\nfunc (g *genericType) String() string {\n\treturn g.s\n}\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tName:    \"kənˈtrīv\",\n\t\tVersion: \"v19.99.0\",\n\t\t/*Authors: []any{\n\t\t\t&cli.Author{\n\t\t\t\tName:  \"Example Human\",\n\t\t\t\tEmail: \"human@example.com\",\n\t\t\t},\n\t\t},*/\n\t\tCopyright: \"(c) 1999 Serious Enterprise\",\n\t\tUsage:     \"demonstrate available API\",\n\t\tUsageText: \"contrive - demonstrating the available API\",\n\t\tArgsUsage: \"[args and such]\",\n\t\tCommands: []*cli.Command{\n\t\t\t&cli.Command{\n\t\t\t\tName:        \"doo\",\n\t\t\t\tAliases:     []string{\"do\"},\n\t\t\t\tCategory:    \"motion\",\n\t\t\t\tUsage:       \"do the doo\",\n\t\t\t\tUsageText:   \"doo - does the dooing\",\n\t\t\t\tDescription: \"no really, there is a lot of dooing to be done\",\n\t\t\t\tArgsUsage:   \"[arrgh]\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"forever\", Aliases: []string{\"forevvarr\"}},\n\t\t\t\t},\n\t\t\t\tCommands: []*cli.Command{\n\t\t\t\t\t&cli.Command{\n\t\t\t\t\t\tName:   \"wop\",\n\t\t\t\t\t\tAction: wopAction,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSkipFlagParsing: false,\n\t\t\t\tHideHelp:        false,\n\t\t\t\tHidden:          false,\n\t\t\t\tShellComplete: func(ctx context.Context, cmd *cli.Command) {\n\t\t\t\t\tfmt.Fprintf(cmd.Root().Writer, \"--better\\n\")\n\t\t\t\t},\n\t\t\t\tBefore: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {\n\t\t\t\t\tfmt.Fprintf(cmd.Root().Writer, \"brace for impact\\n\")\n\t\t\t\t\treturn nil, nil\n\t\t\t\t},\n\t\t\t\tAfter: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Fprintf(cmd.Root().Writer, \"did we lose anyone?\\n\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tcmd.FullName()\n\t\t\t\t\tcmd.HasName(\"wop\")\n\t\t\t\t\tcmd.Names()\n\t\t\t\t\tcmd.VisibleFlags()\n\t\t\t\t\tfmt.Fprintf(cmd.Root().Writer, \"dodododododoodododddooooododododooo\\n\")\n\t\t\t\t\tif cmd.Bool(\"forever\") {\n\t\t\t\t\t\tcmd.Run(ctx, nil)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tOnUsageError: func(ctx context.Context, cmd *cli.Command, err error, isSubcommand bool) error {\n\t\t\t\t\tfmt.Fprintf(cmd.Root().Writer, \"for shame\\n\")\n\t\t\t\t\treturn err\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{Name: \"fancy\"},\n\t\t\t&cli.BoolFlag{Value: true, Name: \"fancier\"},\n\t\t\t&cli.DurationFlag{Name: \"howlong\", Aliases: []string{\"H\"}, Value: time.Second * 3},\n\t\t\t&cli.FloatFlag{Name: \"howmuch\"},\n\t\t\t&cli.IntFlag{Name: \"longdistance\", Validator: func (t int) error {\n\t\t\t\tif t < 10 {\n\t\t\t\t\treturn fmt.Errorf(\"10 miles isn't long distance!!!!\")\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}},\n\t\t\t&cli.IntSliceFlag{Name: \"intervals\"},\n\t\t\t&cli.StringFlag{Name: \"dance-move\", Aliases: []string{\"d\"}, Validator: func(move string) error {\n\t\t\t\tmoves := []string{\"salsa\", \"tap\", \"two-step\", \"lock-step\"}\n\t\t\t\tif !slices.Contains(moves, move) {\n\t\t\t\t\treturn fmt.Errorf(\"Havent learnt %s move yet\", move)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}},\n\t\t\t&cli.StringSliceFlag{Name: \"names\", Aliases: []string{\"N\"}},\n\t\t\t&cli.UintFlag{Name: \"age\"},\n\t\t},\n\t\tEnableShellCompletion: true,\n\t\tHideHelp:              false,\n\t\tHideVersion:           false,\n\t\tShellComplete: func(ctx context.Context, cmd *cli.Command) {\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"lipstick\\nkiss\\nme\\nlipstick\\nringo\\n\")\n\t\t},\n\t\tBefore: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"HEEEERE GOES\\n\")\n\t\t\treturn nil, nil\n\t\t},\n\t\tAfter: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"Phew!\\n\")\n\t\t\treturn nil\n\t\t},\n\t\tCommandNotFound: func(ctx context.Context, cmd *cli.Command, command string) {\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"Thar be no %q here.\\n\", command)\n\t\t},\n\t\tOnUsageError: func(ctx context.Context, cmd *cli.Command, err error, isSubcommand bool) error {\n\t\t\tif isSubcommand {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"WRONG: %#v\\n\", err)\n\t\t\treturn nil\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tcli.DefaultRootCommandComplete(ctx, cmd)\n\t\t\tcli.HandleExitCoder(errors.New(\"not an exit coder, though\"))\n\t\t\tcli.ShowRootCommandHelp(cmd)\n\t\t\tcli.ShowCommandHelp(ctx, cmd, \"also-nope\")\n\t\t\tcli.ShowSubcommandHelp(cmd)\n\t\t\tcli.ShowVersion(cmd)\n\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Root().Command(\"doo\"))\n\t\t\tif cmd.Bool(\"infinite\") {\n\t\t\t\tcmd.Root().Run(ctx, []string{\"app\", \"doo\", \"wop\"})\n\t\t\t}\n\n\t\t\tif cmd.Bool(\"forevar\") {\n\t\t\t\tcmd.Root().Run(ctx, nil)\n\t\t\t}\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Root().VisibleCategories())\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Root().VisibleCommands())\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Root().VisibleFlags())\n\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Args().First())\n\t\t\tif cmd.Args().Len() > 0 {\n\t\t\t\tfmt.Printf(\"%#v\\n\", cmd.Args().Get(1))\n\t\t\t}\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Args().Present())\n\t\t\tfmt.Printf(\"%#v\\n\", cmd.Args().Tail())\n\n\t\t\tec := cli.Exit(\"ohwell\", 86)\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"%d\", ec.ExitCode())\n\t\t\tfmt.Printf(\"made it!\\n\")\n\t\t\treturn ec\n\t\t},\n\t\tMetadata: map[string]interface{}{\n\t\t\t\"layers\":          \"many\",\n\t\t\t\"explicable\":      false,\n\t\t\t\"whatever-values\": 19.99,\n\t\t},\n\t}\n\n\tif os.Getenv(\"HEXY\") != \"\" {\n\t\tcmd.Writer = &hexWriter{}\n\t\tcmd.ErrWriter = &hexWriter{}\n\t}\n\n\tcmd.Run(context.Background(), os.Args)\n}\n\nfunc wopAction(ctx context.Context, cmd *cli.Command) error {\n\tfmt.Fprintf(cmd.Root().Writer, \":wave: over here, eh\\n\")\n\treturn nil\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/greet.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nBeing a programmer can be a lonely job. Thankfully by the power of automation\nthat is not the case! Let's create a greeter app to fend off our demons of\nloneliness!\n\nStart by creating a directory named `greet`, and within it, add a file,\n`greet.go` with the following code in it:\n\n<!-- {\n  \"output\": \"Hello friend!\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tName:  \"greet\",\n\t\tUsage: \"fight the loneliness!\",\n\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\tfmt.Println(\"Hello friend!\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nInstall our command to the `$GOPATH/bin` directory:\n\n```sh-session\n$ go install\n```\n\nFinally run our new command:\n\n```sh-session\n$ greet\nHello friend!\n```\n\ncli also generates neat help text:\n\n```sh-session\n$ greet help\nNAME:\n   greet - fight the loneliness!\n\nUSAGE:\n   greet [global options]\n\nGLOBAL OPTIONS:\n   --help, -h  show help\n```\n\nIn general a full help with flags and subcommands would give something like this\n```\nNAME:\n    greet - fight the loneliness!\n\nUSAGE:\n    greet [global options] command [command options] [arguments...]\n\nCOMMANDS:\n    help, h  Shows a list of commands or help for one command\n\nGLOBAL OPTIONS\n    --help, -h  show help (default: false)\n```\n"
  },
  {
    "path": "docs/v3/examples/help/generated-help-text.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThe default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked\nby the cli internals in order to print generated help text for the app, command,\nor subcommand, and break execution.\n\n#### Customization\n\nAll of the help text generation may be customized, and at multiple levels. The templates\nare exposed as variables `RootCommandHelpTemplate`, `CommandHelpTemplate`, and\n`SubcommandHelpTemplate` which may be reassigned or augmented, and full override is\npossible by assigning a compatible func to the `cli.HelpPrinter` variable, e.g.:\n\n<!-- {\n  \"output\": \"Ha HA.  I pwnd the help!!1\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\t// EXAMPLE: Append to an existing template\n\tcli.RootCommandHelpTemplate = fmt.Sprintf(`%s\n\nWEBSITE: http://awesometown.example.com\n\nSUPPORT: support@awesometown.example.com\n\n`, cli.RootCommandHelpTemplate)\n\n\t// EXAMPLE: Override a template\n\tcli.RootCommandHelpTemplate = `NAME:\n   {{.Name}} - {{.Usage}}\nUSAGE:\n   {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}\n   {{if len .Authors}}\nAUTHOR:\n   {{range .Authors}}{{ . }}{{end}}\n   {{end}}{{if .Commands}}\nCOMMANDS:\n{{range .Commands}}{{if not .HideHelp}}   {{join .Names \", \"}}{{ \"\\t\"}}{{.Usage}}{{ \"\\n\" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}\nGLOBAL OPTIONS:\n   {{range .VisibleFlags}}{{.}}\n   {{end}}{{end}}{{if .Copyright }}\nCOPYRIGHT:\n   {{.Copyright}}\n   {{end}}{{if .Version}}\nVERSION:\n   {{.Version}}\n   {{end}}\n`\n\n\t// EXAMPLE: Replace the `HelpPrinter` func\n\tcli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfmt.Println(\"Ha HA.  I pwnd the help!!1\")\n\t}\n\n\t(&cli.Command{}).Run(context.Background(), os.Args)\n}\n```\n\nThe default flag may be customized to something other than `-h/--help` by\nsetting `cli.HelpFlag`, e.g.:\n\n<!-- {\n  \"args\": [\"&#45;&#45halp\"],\n  \"output\": \"haaaaalp.*HALP\"\n} -->\n```go\npackage main\n\nimport (\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcli.HelpFlag = &cli.BoolFlag{\n\t\tName:    \"haaaaalp\",\n\t\tAliases: []string{\"halp\"},\n\t\tUsage:   \"HALP\",\n\t\tSources: cli.EnvVars(\"SHOW_HALP\", \"HALPPLZ\"),\n\t}\n\n\t(&cli.Command{}).Run(context.Background(), os.Args)\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/help/suggestions.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nTo enable flag and command suggestions, set `Command.Suggest = true`. If the suggest\nfeature is enabled, then the help output of the corresponding command will\nprovide an appropriate suggestion for the provided flag or subcommand if\navailable.\n"
  },
  {
    "path": "docs/v3/examples/subcommands/basics.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nSubcommands can be defined for a more git-like command line app.\n\n<!-- {\n  \"args\": [\"template\", \"add\"],\n  \"output\": \"new task template: .+\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:    \"add\",\n\t\t\t\tAliases: []string{\"a\"},\n\t\t\t\tUsage:   \"add a task to the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"added task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"complete\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tUsage:   \"complete a task on the list\",\n\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"completed task: \", cmd.Args().First())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"template\",\n\t\t\t\tAliases: []string{\"t\"},\n\t\t\t\tUsage:   \"options for task templates\",\n\t\t\t\tCommands: []*cli.Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"add\",\n\t\t\t\t\t\tUsage: \"add a new template\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"new task template: \", cmd.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"remove\",\n\t\t\t\t\t\tUsage: \"remove an existing template\",\n\t\t\t\t\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"removed task template: \", cmd.Args().First())\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n"
  },
  {
    "path": "docs/v3/examples/subcommands/categories.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nFor additional organization in apps that have many subcommands, you can\nassociate a category for each command to group them together in the help\noutput, e.g.:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName: \"noop\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"add\",\n\t\t\t\tCategory: \"template\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"remove\",\n\t\t\t\tCategory: \"template\",\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWill include:\n\n```\nCOMMANDS:\n  noop\n\n  template:\n    add\n    remove\n```\n"
  },
  {
    "path": "docs/v3/getting-started.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nOne of the philosophies behind cli is that an API should be playful and full of\ndiscovery. So a cli app can be as little as one line of code in `main()`.\n\n<!-- {\n  \"args\": [\"&#45;&#45;help\"],\n  \"output\": \"A new cli application\"\n} -->\n```go\npackage main\n\nimport (\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\t(&cli.Command{}).Run(context.Background(), os.Args)\n}\n```\n\nThis app will run and show help text, but is not very useful.\n\n```\n$ wl-paste > hello.go\n$ go build hello.go\n$ ./hello\nNAME:\n   hello - A new cli application\n\nUSAGE:\n   hello [global options]\n\nGLOBAL OPTIONS:\n   --help, -h  show help\n```\n\nLet's add an action to execute and some help documentation:\n\n<!-- {\n  \"output\": \"boom! I say!\"\n} -->\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\tcmd := &cli.Command{\n\t\tName:  \"boom\",\n\t\tUsage: \"make an explosive entrance\",\n\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\tfmt.Println(\"boom! I say!\")\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\nThe output of above code is \n\n```\nboom! I say!\n```\n\nRunning this already gives you a ton of functionality, plus support for things\nlike subcommands and flags, which are covered in a separate section. \n"
  },
  {
    "path": "docs/v3/index.md",
    "content": "# v3 guide\n"
  },
  {
    "path": "docs/v3/migrating-from-older-releases.md",
    "content": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThere are a small set of breaking changes between v1 and v3.  Converting is\nrelatively straightforward and typically takes less than an hour. Specific steps\nare included in [Migration Guide: v2 to v3](../migrate-v2-to-v3.md). Also see\nthe [pkg.go.dev docs](https://pkg.go.dev/github.com/urfave/cli/v3) for v3 API\ndocumentation.\n"
  },
  {
    "path": "docs.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nfunc prefixFor(name string) (prefix string) {\n\tif len(name) == 1 {\n\t\tprefix = \"-\"\n\t} else {\n\t\tprefix = \"--\"\n\t}\n\n\treturn prefix\n}\n\n// Returns the placeholder, if any, and the unquoted usage string.\nfunc unquoteUsage(usage string) (string, string) {\n\tfor i := 0; i < len(usage); i++ {\n\t\tif usage[i] == '`' {\n\t\t\tfor j := i + 1; j < len(usage); j++ {\n\t\t\t\tif usage[j] == '`' {\n\t\t\t\t\tname := usage[i+1 : j]\n\t\t\t\t\tusage = usage[:i] + name + usage[j+1:]\n\t\t\t\t\treturn name, usage\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\treturn \"\", usage\n}\n\nfunc prefixedNames(names []string, placeholder string) string {\n\tvar prefixed string\n\tfor i, name := range names {\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tprefixed += prefixFor(name) + name\n\t\tif placeholder != \"\" {\n\t\t\tprefixed += \" \" + placeholder\n\t\t}\n\t\tif i < len(names)-1 {\n\t\t\tprefixed += \", \"\n\t\t}\n\t}\n\treturn prefixed\n}\n\nfunc envFormat(envVars []string, prefix, sep, suffix string) string {\n\tif len(envVars) > 0 {\n\t\treturn fmt.Sprintf(\" [%s%s%s]\", prefix, strings.Join(envVars, sep), suffix)\n\t}\n\treturn \"\"\n}\n\nfunc defaultEnvFormat(envVars []string) string {\n\treturn envFormat(envVars, \"$\", \", $\", \"\")\n}\n\nfunc withEnvHint(envVars []string, str string) string {\n\tenvText := \"\"\n\tif runtime.GOOS != \"windows\" || os.Getenv(\"PSHOME\") != \"\" {\n\t\tenvText = defaultEnvFormat(envVars)\n\t} else {\n\t\tenvText = envFormat(envVars, \"%\", \"%, %\", \"%\")\n\t}\n\treturn str + envText\n}\n\nfunc withFileHint(filePath, str string) string {\n\tfileText := \"\"\n\tif filePath != \"\" {\n\t\tfileText = fmt.Sprintf(\" [%s]\", filePath)\n\t}\n\treturn str + fileText\n}\n\nfunc formatDefault(format string) string {\n\treturn \" (default: \" + format + \")\"\n}\n\nfunc stringifyFlag(f Flag) string {\n\t// enforce DocGeneration interface on flags to avoid reflection\n\tdf, ok := f.(DocGenerationFlag)\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tplaceholder, usage := unquoteUsage(df.GetUsage())\n\tneedsPlaceholder := df.TakesValue()\n\t// if needsPlaceholder is true, placeholder is empty\n\tif needsPlaceholder && placeholder == \"\" {\n\t\t// try to get type from flag\n\t\tif tname := df.TypeName(); tname != \"\" {\n\t\t\tplaceholder = tname\n\t\t} else {\n\t\t\tplaceholder = defaultPlaceholder\n\t\t}\n\t}\n\n\tdefaultValueString := \"\"\n\n\t// don't print default text for required flags\n\tif rf, ok := f.(RequiredFlag); !ok || !rf.IsRequired() {\n\t\tif df.IsDefaultVisible() {\n\t\t\tif s := df.GetDefaultText(); s != \"\" {\n\t\t\t\tdefaultValueString = fmt.Sprintf(formatDefault(\"%s\"), s)\n\t\t\t} else if df.TakesValue() && df.GetValue() != \"\" {\n\t\t\t\tdefaultValueString = fmt.Sprintf(formatDefault(\"%s\"), df.GetValue())\n\t\t\t}\n\t\t}\n\t}\n\n\tusageWithDefault := strings.TrimSpace(usage + defaultValueString)\n\n\tpn := prefixedNames(f.Names(), placeholder)\n\tsliceFlag, ok := f.(DocGenerationMultiValueFlag)\n\tif ok && sliceFlag.IsMultiValueFlag() {\n\t\tpn = pn + \" [ \" + pn + \" ]\"\n\t}\n\n\treturn withEnvHint(df.GetEnvVars(), fmt.Sprintf(\"%s\\t%s\", pn, usageWithDefault))\n}\n"
  },
  {
    "path": "errors.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\n// OsExiter is the function used when the app exits. If not set defaults to os.Exit.\nvar OsExiter = os.Exit\n\n// ErrWriter is used to write errors to the user. This can be anything\n// implementing the io.Writer interface and defaults to os.Stderr.\nvar ErrWriter io.Writer = os.Stderr\n\n// MultiError is an error that wraps multiple errors.\ntype MultiError interface {\n\terror\n\tErrors() []error\n}\n\n// newMultiError creates a new MultiError. Pass in one or more errors.\nfunc newMultiError(err ...error) MultiError {\n\tret := multiError(err)\n\treturn &ret\n}\n\ntype multiError []error\n\n// Error implements the error interface.\nfunc (m *multiError) Error() string {\n\terrs := make([]string, len(*m))\n\tfor i, err := range *m {\n\t\terrs[i] = err.Error()\n\t}\n\n\treturn strings.Join(errs, \"\\n\")\n}\n\n// Errors returns a copy of the errors slice\nfunc (m *multiError) Errors() []error {\n\terrs := make([]error, len(*m))\n\tcopy(errs, *m)\n\treturn errs\n}\n\ntype requiredFlagsErr interface {\n\terror\n}\n\ntype errRequiredFlags struct {\n\tmissingFlags []string\n}\n\nfunc (e *errRequiredFlags) Error() string {\n\tif len(e.missingFlags) == 1 {\n\t\treturn fmt.Sprintf(\"Required flag %q not set\", e.missingFlags[0])\n\t}\n\tjoinedMissingFlags := strings.Join(e.missingFlags, \", \")\n\treturn fmt.Sprintf(\"Required flags %q not set\", joinedMissingFlags)\n}\n\ntype mutuallyExclusiveGroup struct {\n\tflag1Name string\n\tflag2Name string\n}\n\nfunc (e *mutuallyExclusiveGroup) Error() string {\n\treturn fmt.Sprintf(\"option %s cannot be set along with option %s\", e.flag1Name, e.flag2Name)\n}\n\ntype mutuallyExclusiveGroupRequiredFlag struct {\n\tflags *MutuallyExclusiveFlags\n}\n\nfunc (e *mutuallyExclusiveGroupRequiredFlag) Error() string {\n\tvar missingFlags []string\n\tfor _, grpf := range e.flags.Flags {\n\t\tvar grpString []string\n\t\tfor _, f := range grpf {\n\t\t\tgrpString = append(grpString, f.Names()...)\n\t\t}\n\t\tmissingFlags = append(missingFlags, strings.Join(grpString, \" \"))\n\t}\n\n\treturn fmt.Sprintf(\"one of these flags needs to be provided: %s\", strings.Join(missingFlags, \", \"))\n}\n\n// ErrorFormatter is the interface that will suitably format the error output\ntype ErrorFormatter interface {\n\tFormat(s fmt.State, verb rune)\n}\n\n// ExitCoder is the interface checked by `Command` for a custom exit code.\ntype ExitCoder interface {\n\terror\n\tExitCode() int\n}\n\ntype exitError struct {\n\texitCode int\n\terr      error\n}\n\n// Exit wraps a message and exit code into an error, which by default is\n// handled with a call to os.Exit during default error handling.\n//\n// This is the simplest way to trigger a non-zero exit code for a Command without\n// having to call os.Exit manually. During testing, this behavior can be avoided\n// by overriding the ExitErrHandler function on a Command or the package-global\n// OsExiter function.\nfunc Exit(message any, exitCode int) ExitCoder {\n\tvar err error\n\n\tswitch e := message.(type) {\n\tcase ErrorFormatter:\n\t\terr = fmt.Errorf(\"%+v\", message)\n\tcase error:\n\t\terr = e\n\tdefault:\n\t\terr = fmt.Errorf(\"%+v\", message)\n\t}\n\n\treturn &exitError{\n\t\terr:      err,\n\t\texitCode: exitCode,\n\t}\n}\n\nfunc (ee *exitError) Error() string {\n\treturn ee.err.Error()\n}\n\nfunc (ee *exitError) ExitCode() int {\n\treturn ee.exitCode\n}\n\n// HandleExitCoder handles errors implementing ExitCoder by printing their\n// message and calling OsExiter with the given exit code.\n//\n// If the given error instead implements MultiError, each error will be checked\n// for the ExitCoder interface, and OsExiter will be called with the last exit\n// code found, or exit code 1 if no ExitCoder is found.\n//\n// This function is the default error-handling behavior for a Command.\nfunc HandleExitCoder(err error) {\n\tif err == nil {\n\t\treturn\n\t}\n\n\tif exitErr, ok := err.(ExitCoder); ok {\n\t\tif _, ok := exitErr.(ErrorFormatter); ok {\n\t\t\t_, _ = fmt.Fprintf(ErrWriter, \"%+v\\n\", err)\n\t\t} else {\n\t\t\t_, _ = fmt.Fprintln(ErrWriter, err)\n\t\t}\n\t\tOsExiter(exitErr.ExitCode())\n\t\treturn\n\t}\n\n\tif multiErr, ok := err.(MultiError); ok {\n\t\tcode := handleMultiError(multiErr)\n\t\tOsExiter(code)\n\t\treturn\n\t}\n}\n\nfunc handleMultiError(multiErr MultiError) int {\n\tcode := 1\n\tfor _, merr := range multiErr.Errors() {\n\t\tif multiErr2, ok := merr.(MultiError); ok {\n\t\t\tcode = handleMultiError(multiErr2)\n\t\t} else if merr != nil {\n\t\t\tfmt.Fprintln(ErrWriter, merr)\n\t\t\tif exitErr, ok := merr.(ExitCoder); ok {\n\t\t\t\tcode = exitErr.ExitCode()\n\t\t\t}\n\t\t}\n\t}\n\treturn code\n}\n"
  },
  {
    "path": "errors_test.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestHandleExitCoder_nil(t *testing.T) {\n\texitCode := 0\n\tcalled := false\n\n\tOsExiter = func(rc int) {\n\t\tif !called {\n\t\t\texitCode = rc\n\t\t\tcalled = true\n\t\t}\n\t}\n\n\tdefer func() { OsExiter = fakeOsExiter }()\n\n\tHandleExitCoder(nil)\n\n\tassert.Equal(t, 0, exitCode)\n\tassert.False(t, called)\n}\n\nfunc TestHandleExitCoder_ExitCoder(t *testing.T) {\n\texitCode := 0\n\tcalled := false\n\n\tOsExiter = func(rc int) {\n\t\tif !called {\n\t\t\texitCode = rc\n\t\t\tcalled = true\n\t\t}\n\t}\n\n\tdefer func() { OsExiter = fakeOsExiter }()\n\n\tHandleExitCoder(Exit(\"galactic perimeter breach\", 9))\n\n\tassert.Equal(t, 9, exitCode)\n\tassert.True(t, called)\n}\n\nfunc TestHandleExitCoder_ErrorExitCoder(t *testing.T) {\n\texitCode := 0\n\tcalled := false\n\n\tOsExiter = func(rc int) {\n\t\tif !called {\n\t\t\texitCode = rc\n\t\t\tcalled = true\n\t\t}\n\t}\n\n\tdefer func() { OsExiter = fakeOsExiter }()\n\n\tHandleExitCoder(Exit(errors.New(\"galactic perimeter breach\"), 9))\n\n\tassert.Equal(t, 9, exitCode)\n\tassert.True(t, called)\n}\n\nfunc TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {\n\texitCode := 0\n\tcalled := false\n\n\tOsExiter = func(rc int) {\n\t\tif !called {\n\t\t\texitCode = rc\n\t\t\tcalled = true\n\t\t}\n\t}\n\n\tdefer func() { OsExiter = fakeOsExiter }()\n\n\texitErr := Exit(\"galactic perimeter breach\", 9)\n\texitErr2 := Exit(\"last ExitCoder\", 11)\n\n\terr := newMultiError(errors.New(\"wowsa\"), errors.New(\"egad\"), exitErr, exitErr2)\n\tHandleExitCoder(err)\n\n\tassert.Equal(t, 11, exitCode)\n\tassert.True(t, called)\n}\n\ntype exitFormatter struct {\n\tcode int\n}\n\nfunc (f *exitFormatter) Format(s fmt.State, verb rune) {\n\t_, _ = s.Write([]byte(\"some other special\"))\n}\n\nfunc (f *exitFormatter) ExitCode() int {\n\treturn f.code\n}\n\nfunc (f *exitFormatter) Error() string {\n\treturn fmt.Sprintf(\"my special error code %d\", f.code)\n}\n\nfunc TestHandleExitCoder_ErrorFormatter(t *testing.T) {\n\texitCode := 0\n\tcalled := false\n\n\tOsExiter = func(rc int) {\n\t\tif !called {\n\t\t\texitCode = rc\n\t\t\tcalled = true\n\t\t}\n\t}\n\n\toldWriter := ErrWriter\n\tvar buf bytes.Buffer\n\tErrWriter = &buf\n\tdefer func() {\n\t\tOsExiter = fakeOsExiter\n\t\tErrWriter = oldWriter\n\t}()\n\n\texitErr := Exit(\"galactic perimeter breach\", 9)\n\texitErr2 := Exit(\"last ExitCoder\", 11)\n\texitErr3 := &exitFormatter{code: 12}\n\n\t// add some recursion for multi error to fix test coverage\n\terr := newMultiError(errors.New(\"wowsa\"), errors.New(\"egad\"), exitErr3, newMultiError(exitErr, exitErr2))\n\tHandleExitCoder(err)\n\n\tassert.Equal(t, 11, exitCode)\n\tassert.True(t, called)\n\tassert.Contains(t, buf.String(), \"some other special\")\n}\n\nfunc TestHandleExitCoder_MultiErrorWithoutExitCoder(t *testing.T) {\n\texitCode := 0\n\tcalled := false\n\n\tOsExiter = func(rc int) {\n\t\tif !called {\n\t\t\texitCode = rc\n\t\t\tcalled = true\n\t\t}\n\t}\n\n\tdefer func() { OsExiter = fakeOsExiter }()\n\n\terr := newMultiError(errors.New(\"wowsa\"), errors.New(\"egad\"))\n\tHandleExitCoder(err)\n\n\tassert.Equal(t, 1, exitCode)\n\tassert.True(t, called)\n}\n\n// make a stub to not import pkg/errors\ntype ErrorWithFormat struct {\n\terror\n}\n\nfunc NewErrorWithFormat(m string) *ErrorWithFormat {\n\treturn &ErrorWithFormat{error: errors.New(m)}\n}\n\nfunc (f *ErrorWithFormat) Format(s fmt.State, verb rune) {\n\tfmt.Fprintf(s, \"This the format: %v\", f.error)\n}\n\nfunc TestHandleExitCoder_ErrorWithFormat(t *testing.T) {\n\tcalled := false\n\n\tOsExiter = func(int) {\n\t\tif !called {\n\t\t\tcalled = true\n\t\t}\n\t}\n\tErrWriter = &bytes.Buffer{}\n\n\tdefer func() {\n\t\tOsExiter = fakeOsExiter\n\t\tErrWriter = fakeErrWriter\n\t}()\n\n\terr := Exit(NewErrorWithFormat(\"I am formatted\"), 1)\n\tHandleExitCoder(err)\n\n\tassert.True(t, called)\n\tassert.Equal(t, ErrWriter.(*bytes.Buffer).String(), \"This the format: I am formatted\\n\")\n}\n\nfunc TestHandleExitCoder_MultiErrorWithFormat(t *testing.T) {\n\tcalled := false\n\n\tOsExiter = func(int) {\n\t\tif !called {\n\t\t\tcalled = true\n\t\t}\n\t}\n\tErrWriter = &bytes.Buffer{}\n\n\tdefer func() { OsExiter = fakeOsExiter }()\n\n\terr := newMultiError(NewErrorWithFormat(\"err1\"), NewErrorWithFormat(\"err2\"))\n\tHandleExitCoder(err)\n\n\tassert.True(t, called)\n\tassert.Equal(t, ErrWriter.(*bytes.Buffer).String(), \"This the format: err1\\nThis the format: err2\\n\")\n}\n\nfunc TestMultiErrorErrorsCopy(t *testing.T) {\n\terrList := []error{\n\t\terrors.New(\"foo\"),\n\t\terrors.New(\"bar\"),\n\t\terrors.New(\"baz\"),\n\t}\n\tme := newMultiError(errList...)\n\tassert.Equal(t, errList, me.Errors())\n}\n\nfunc TestErrRequiredFlags_Error(t *testing.T) {\n\tmissingFlags := []string{\"flag1\", \"flag2\"}\n\terr := &errRequiredFlags{missingFlags: missingFlags}\n\texpectedMsg := \"Required flags \\\"flag1, flag2\\\" not set\"\n\tassert.Equal(t, expectedMsg, err.Error())\n\n\tmissingFlags = []string{\"flag1\"}\n\terr = &errRequiredFlags{missingFlags: missingFlags}\n\texpectedMsg = \"Required flag \\\"flag1\\\" not set\"\n\tassert.Equal(t, expectedMsg, err.Error())\n}\n"
  },
  {
    "path": "examples/example-cli/example-cli.go",
    "content": "// minimal example CLI used for binary size checking\n\npackage main\n\nimport (\n\t\"context\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nfunc main() {\n\t_ = (&cli.Command{}).Run(context.Background(), []string{\"\"})\n}\n"
  },
  {
    "path": "examples/example-hello-world/example-hello-world.go",
    "content": "// example hello world used for binary size checking\n\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"hello world\")\n}\n"
  },
  {
    "path": "examples_test.go",
    "content": "package cli_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/mail\"\n\t\"os\"\n\t\"time\"\n\n\t// Alias the package import to make the examples runnable on pkg.go.dev.\n\t//\n\t// See issue #1811.\n\tcli \"github.com/urfave/cli/v3\"\n)\n\nfunc ExampleCommand_Run() {\n\t// Declare a command\n\tcmd := &cli.Command{\n\t\tName: \"greet\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{Name: \"name\", Value: \"pat\", Usage: \"a name to say\"},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"Hello %[1]v\\n\", cmd.String(\"name\"))\n\t\t\treturn nil\n\t\t},\n\t\tAuthors: []any{\n\t\t\t&mail.Address{Name: \"Oliver Allen\", Address: \"oliver@toyshop.example.com\"},\n\t\t\t\"gruffalo@soup-world.example.org\",\n\t\t},\n\t\tVersion: \"v0.13.12\",\n\t}\n\n\t// Simulate the command line arguments\n\tos.Args = []string{\"greet\", \"--name\", \"Jeremy\"}\n\n\tif err := cmd.Run(context.Background(), os.Args); err != nil {\n\t\t// do something with unhandled errors\n\t\tfmt.Fprintf(os.Stderr, \"Unhandled error: %[1]v\\n\", err)\n\t\tos.Exit(86)\n\t}\n\t// Output:\n\t// Hello Jeremy\n}\n\nfunc ExampleCommand_Run_subcommand() {\n\tcmd := &cli.Command{\n\t\tName: \"say\",\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"hello\",\n\t\t\t\tAliases:     []string{\"hi\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tDescription: \"This is how we describe hello the function\",\n\t\t\t\tCommands: []*cli.Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"english\",\n\t\t\t\t\t\tAliases:     []string{\"en\"},\n\t\t\t\t\t\tUsage:       \"sends a greeting in english\",\n\t\t\t\t\t\tDescription: \"greets someone in english\",\n\t\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\t\t\tName:  \"name\",\n\t\t\t\t\t\t\t\tValue: \"Bob\",\n\t\t\t\t\t\t\t\tUsage: \"Name of the person to greet\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\t\t\tfmt.Println(\"Hello,\", cmd.String(\"name\"))\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\n\tdefer cancel()\n\n\t// Simulate the command line arguments\n\tos.Args = []string{\"say\", \"hi\", \"english\", \"--name\", \"Jeremy\"}\n\n\t_ = cmd.Run(ctx, os.Args)\n\t// Output:\n\t// Hello, Jeremy\n}\n\nfunc ExampleCommand_Run_appHelp() {\n\tcmd := &cli.Command{\n\t\tName:        \"greet\",\n\t\tVersion:     \"0.1.0\",\n\t\tDescription: \"This is how we describe greet the app\",\n\t\tAuthors: []any{\n\t\t\t&mail.Address{Name: \"Harrison\", Address: \"harrison@lolwut.example.com\"},\n\t\t\t\"Oliver Allen  <oliver@toyshop.example.com>\",\n\t\t},\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{Name: \"name\", Value: \"bob\", Usage: \"a name to say\"},\n\t\t},\n\t\tArguments: cli.AnyArguments,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"describeit\",\n\t\t\t\tAliases:     []string{\"d\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tDescription: \"This is how we describe describeit the function\",\n\t\t\t\tArgsUsage:   \"[arguments...]\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"i like to describe things\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\n\tdefer cancel()\n\n\t// Simulate the command line arguments\n\tos.Args = []string{\"greet\", \"help\"}\n\n\t_ = cmd.Run(ctx, os.Args)\n\t// Output:\n\t// NAME:\n\t//    greet - A new cli application\n\t//\n\t// USAGE:\n\t//    greet [global options] [command [command options]] [arguments...]\n\t//\n\t// VERSION:\n\t//    0.1.0\n\t//\n\t// DESCRIPTION:\n\t//    This is how we describe greet the app\n\t//\n\t// AUTHORS:\n\t//    \"Harrison\" <harrison@lolwut.example.com>\n\t//    Oliver Allen  <oliver@toyshop.example.com>\n\t//\n\t// COMMANDS:\n\t//    describeit, d  use it to see a description\n\t//    help, h        Shows a list of commands or help for one command\n\t//\n\t// GLOBAL OPTIONS:\n\t//    --name string  a name to say (default: \"bob\")\n\t//    --help, -h     show help\n\t//    --version, -v  print the version\n}\n\nfunc ExampleCommand_Run_commandHelp() {\n\tcmd := &cli.Command{\n\t\tName: \"greet\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{Name: \"name\", Value: \"pat\", Usage: \"a name to say\"},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Fprintf(cmd.Root().Writer, \"hello to %[1]q\\n\", cmd.String(\"name\"))\n\t\t\treturn nil\n\t\t},\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"describeit\",\n\t\t\t\tAliases:     []string{\"d\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tDescription: \"This is how we describe describeit the function\",\n\t\t\t\tArgsUsage:   \"[arguments...]\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Println(\"i like to describe things\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate the command line arguments\n\tos.Args = []string{\"greet\", \"h\", \"describeit\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// NAME:\n\t//    greet describeit - use it to see a description\n\t//\n\t// USAGE:\n\t//    greet describeit [arguments...]\n\t//\n\t// DESCRIPTION:\n\t//    This is how we describe describeit the function\n\t//\n\t// OPTIONS:\n\t//    --help, -h  show help\n}\n\nfunc ExampleCommand_Run_noAction() {\n\tcmd := &cli.Command{Name: \"greet\"}\n\n\t// Simulate the command line arguments\n\tos.Args = []string{\"greet\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// NAME:\n\t//    greet - A new cli application\n\t//\n\t// USAGE:\n\t//    greet [global options]\n\t//\n\t// GLOBAL OPTIONS:\n\t//    --help, -h  show help\n}\n\nfunc ExampleCommand_Run_subcommandNoAction() {\n\tcmd := &cli.Command{\n\t\tName: \"greet\",\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"describeit\",\n\t\t\t\tAliases:     []string{\"d\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tArgsUsage:   \"[arguments...]\",\n\t\t\t\tDescription: \"This is how we describe describeit the function\",\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate the command line arguments\n\tos.Args = []string{\"greet\", \"describeit\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// NAME:\n\t//    greet describeit - use it to see a description\n\t//\n\t// USAGE:\n\t//    greet describeit [options] [arguments...]\n\t//\n\t// DESCRIPTION:\n\t//    This is how we describe describeit the function\n\t//\n\t// OPTIONS:\n\t//    --help, -h  show help\n}\n\nfunc ExampleCommand_Run_shellComplete_bash_withShortFlag() {\n\tcmd := &cli.Command{\n\t\tName:                  \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.Int64Flag{\n\t\t\t\tName:    \"other\",\n\t\t\t\tAliases: []string{\"o\"},\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"xyz\",\n\t\t\t\tAliases: []string{\"x\"},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate a bash environment and command line arguments\n\tos.Setenv(\"SHELL\", \"bash\")\n\tos.Args = []string{\"greet\", \"-\", \"--generate-shell-completion\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// --other\n\t// --xyz\n\t// --help\n}\n\nfunc ExampleCommand_Run_shellComplete_bash_withLongFlag() {\n\tcmd := &cli.Command{\n\t\tName:                  \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.Int64Flag{\n\t\t\t\tName:    \"other\",\n\t\t\t\tAliases: []string{\"o\"},\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"xyz\",\n\t\t\t\tAliases: []string{\"x\"},\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName: \"some-flag,s\",\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName: \"similar-flag\",\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate a bash environment and command line arguments\n\tos.Setenv(\"SHELL\", \"bash\")\n\tos.Args = []string{\"greet\", \"--s\", \"--generate-shell-completion\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// --some-flag\n\t// --similar-flag\n}\n\nfunc ExampleCommand_Run_shellComplete_bash_withMultipleLongFlag() {\n\tcmd := &cli.Command{\n\t\tName:                  \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.Int64Flag{\n\t\t\t\tName:    \"int-flag\",\n\t\t\t\tAliases: []string{\"i\"},\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"string\",\n\t\t\t\tAliases: []string{\"s\"},\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName: \"string-flag-2\",\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName: \"similar-flag\",\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName: \"some-flag\",\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate a bash environment and command line arguments\n\tos.Setenv(\"SHELL\", \"bash\")\n\tos.Args = []string{\"greet\", \"--st\", \"--generate-shell-completion\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// --string\n\t// --string-flag-2\n}\n\nfunc ExampleCommand_Run_shellComplete_bash() {\n\tcmd := &cli.Command{\n\t\tName:                  \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"describeit\",\n\t\t\t\tAliases:     []string{\"d\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tDescription: \"This is how we describe describeit the function\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"i like to describe things\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, {\n\t\t\t\tName:        \"next\",\n\t\t\t\tUsage:       \"next example\",\n\t\t\t\tDescription: \"more stuff to see when generating shell completion\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"the next example\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate a bash environment and command line arguments\n\tos.Setenv(\"SHELL\", \"bash\")\n\tos.Args = []string{\"greet\", \"--generate-shell-completion\"}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// describeit\n\t// next\n\t// help\n}\n\nfunc ExampleCommand_Run_shellComplete_zsh() {\n\tcmd := &cli.Command{\n\t\tName:                  \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"describeit\",\n\t\t\t\tAliases:     []string{\"d\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tDescription: \"This is how we describe describeit the function\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"i like to describe things\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, {\n\t\t\t\tName:        \"next\",\n\t\t\t\tUsage:       \"next example\",\n\t\t\t\tDescription: \"more stuff to see when generating bash completion\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"the next example\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate a zsh environment and command line arguments\n\tos.Args = []string{\"greet\", \"--generate-shell-completion\"}\n\tos.Setenv(\"SHELL\", \"/usr/bin/zsh\")\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// describeit:use it to see a description\n\t// next:next example\n\t// help:Shows a list of commands or help for one command\n}\n\nfunc ExampleCommand_Run_shellComplete_fish() {\n\tcmd := &cli.Command{\n\t\tName:                  \"greet\",\n\t\tEnableShellCompletion: true,\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:        \"describeit\",\n\t\t\t\tAliases:     []string{\"d\"},\n\t\t\t\tUsage:       \"use it to see a description\",\n\t\t\t\tDescription: \"This is how we describe describeit the function\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"i like to describe things\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, {\n\t\t\t\tName:        \"next\",\n\t\t\t\tUsage:       \"next example\",\n\t\t\t\tDescription: \"more stuff to see when generating bash completion\",\n\t\t\t\tAction: func(context.Context, *cli.Command) error {\n\t\t\t\t\tfmt.Printf(\"the next example\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Simulate a fish environment and command line arguments\n\tos.Args = []string{\"greet\", \"--generate-shell-completion\"}\n\tos.Setenv(\"SHELL\", \"/usr/bin/fish\")\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// describeit:use it to see a description\n\t// next:next example\n\t// help:Shows a list of commands or help for one command\n}\n\nfunc ExampleCommand_Run_sliceValues() {\n\tcmd := &cli.Command{\n\t\tName: \"multi_values\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringSliceFlag{Name: \"stringSlice\"},\n\t\t\t&cli.FloatSliceFlag{Name: \"float64Slice\"},\n\t\t\t&cli.Int64SliceFlag{Name: \"intSlice\"},\n\t\t},\n\t\tHideHelp: true,\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfor i, v := range cmd.FlagNames() {\n\t\t\t\tfmt.Printf(\"%d-%s %#v\\n\", i, v, cmd.Value(v))\n\t\t\t}\n\t\t\terr := ctx.Err()\n\t\t\tfmt.Println(\"error:\", err)\n\t\t\treturn err\n\t\t},\n\t}\n\n\t// Simulate command line arguments\n\tos.Args = []string{\n\t\t\"multi_values\",\n\t\t\"--stringSlice\", \"parsed1,parsed2\", \"--stringSlice\", \"parsed3,parsed4\",\n\t\t\"--float64Slice\", \"13.3,14.4\", \"--float64Slice\", \"15.5,16.6\",\n\t\t\"--intSlice\", \"13,14\", \"--intSlice\", \"15,16\",\n\t}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// 0-stringSlice []string{\"parsed1\", \"parsed2\", \"parsed3\", \"parsed4\"}\n\t// 1-float64Slice []float64{13.3, 14.4, 15.5, 16.6}\n\t// 2-intSlice []int64{13, 14, 15, 16}\n\t// error: <nil>\n}\n\nfunc ExampleCommand_Run_mapValues() {\n\tcmd := &cli.Command{\n\t\tName: \"multi_values\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringMapFlag{Name: \"stringMap\"},\n\t\t},\n\t\tHideHelp: true,\n\t\tAction: func(ctx context.Context, cmd *cli.Command) error {\n\t\t\tfor i, v := range cmd.FlagNames() {\n\t\t\t\tfmt.Printf(\"%d-%s %#v\\n\", i, v, cmd.StringMap(v))\n\t\t\t}\n\t\t\tfmt.Printf(\"notfound %#v\\n\", cmd.StringMap(\"notfound\"))\n\t\t\terr := ctx.Err()\n\t\t\tfmt.Println(\"error:\", err)\n\t\t\treturn err\n\t\t},\n\t}\n\n\t// Simulate command line arguments\n\tos.Args = []string{\n\t\t\"multi_values\",\n\t\t\"--stringMap\", \"parsed1=parsed two\", \"--stringMap\", \"parsed3=\",\n\t}\n\n\t_ = cmd.Run(context.Background(), os.Args)\n\t// Output:\n\t// 0-stringMap map[string]string{\"parsed1\":\"parsed two\", \"parsed3\":\"\"}\n\t// notfound map[string]string(nil)\n\t// error: <nil>\n}\n\nfunc ExampleBoolWithInverseFlag() {\n\tflagWithInverse := &cli.BoolWithInverseFlag{\n\t\tName: \"env\",\n\t}\n\n\tcmd := &cli.Command{\n\t\tFlags: []cli.Flag{\n\t\t\tflagWithInverse,\n\t\t},\n\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\tif flagWithInverse.IsSet() {\n\t\t\t\tif cmd.Bool(\"env\") {\n\t\t\t\t\tfmt.Println(\"env is set\")\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Println(\"no-env is set\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n\n\t_ = cmd.Run(context.Background(), []string{\"prog\", \"--no-env\"})\n\n\tfmt.Println(\"flags:\", len(flagWithInverse.Names()))\n\n\t// Output:\n\t// no-env is set\n\t// flags: 2\n}\n\nfunc ExampleCommand_Suggest() {\n\tcmd := &cli.Command{\n\t\tName:                          \"greet\",\n\t\tErrWriter:                     os.Stdout,\n\t\tSuggest:                       true,\n\t\tHideHelp:                      false,\n\t\tHideHelpCommand:               true,\n\t\tCustomRootCommandHelpTemplate: \"(this space intentionally left blank)\\n\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{Name: \"name\", Value: \"squirrel\", Usage: \"a name to say\"},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"Hello %v\\n\", cmd.String(\"name\"))\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tif cmd.Run(context.Background(), []string{\"greet\", \"--nema\", \"chipmunk\"}) == nil {\n\t\tfmt.Println(\"Expected error\")\n\t}\n\t// Output:\n\t// Incorrect Usage: flag provided but not defined: -nema\n\t//\n\t// Did you mean \"--name\"?\n\t//\n\t// (this space intentionally left blank)\n}\n\nfunc ExampleCommand_Suggest_command() {\n\tcmd := &cli.Command{\n\t\tErrWriter: os.Stdout,\n\t\tName:      \"greet\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{Name: \"name\", Value: \"squirrel\", Usage: \"a name to say\"},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\tfmt.Printf(\"Hello %v\\n\", cmd.String(\"name\"))\n\t\t\treturn nil\n\t\t},\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:               \"neighbors\",\n\t\t\t\tHideHelp:           true,\n\t\t\t\tHideHelpCommand:    true,\n\t\t\t\tSuggest:            true,\n\t\t\t\tCustomHelpTemplate: \"(this space intentionally left blank)\\n\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"smiling\"},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\tif cmd.Bool(\"smiling\") {\n\t\t\t\t\t\tfmt.Println(\"😀\")\n\t\t\t\t\t}\n\t\t\t\t\tfmt.Println(\"Hello, neighbors\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif cmd.Run(context.Background(), []string{\"greet\", \"neighbors\", \"--sliming\"}) == nil {\n\t\tfmt.Println(\"Expected error\")\n\t}\n\t// Output:\n\t// Incorrect Usage: flag provided but not defined: -sliming\n\t//\n\t// Did you mean \"--smiling\"?\n}\n"
  },
  {
    "path": "fish.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"text/template\"\n)\n\n// ToFishCompletion creates a fish completion string for the `*Command`\n// The function errors if either parsing or writing of the string fails.\nfunc (cmd *Command) ToFishCompletion() (string, error) {\n\tvar w bytes.Buffer\n\tif err := cmd.writeFishCompletionTemplate(&w); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn w.String(), nil\n}\n\ntype fishCommandCompletionTemplate struct {\n\tCommand     *Command\n\tCompletions []string\n\tAllCommands []string\n}\n\nfunc (cmd *Command) writeFishCompletionTemplate(w io.Writer) error {\n\tconst name = \"cli\"\n\tt, err := template.New(name).Parse(FishCompletionTemplate)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Add global flags\n\tcompletions := prepareFishFlags(cmd.Name, cmd)\n\n\tif cmd.ShellComplete != nil {\n\t\tvar completion strings.Builder\n\t\tfmt.Fprintf(&completion,\n\t\t\t\"complete -c %s -n '%s' -xa '(%s %s 2>/dev/null)'\",\n\t\t\tcmd.Name,\n\t\t\tfishFlagHelper(cmd.Name, cmd),\n\t\t\tcmd.Name,\n\t\t\tcompletionFlag,\n\t\t)\n\t\tcompletions = append(completions, completion.String())\n\t}\n\n\t// Add commands and their flags\n\tcompletions = append(\n\t\tcompletions,\n\t\tprepareFishCommands(cmd.Name, cmd)...,\n\t)\n\n\ttoplevelCommandNames := []string{}\n\tfor _, child := range cmd.Commands {\n\t\ttoplevelCommandNames = append(toplevelCommandNames, child.Names()...)\n\t}\n\n\treturn t.ExecuteTemplate(w, name, &fishCommandCompletionTemplate{\n\t\tCommand:     cmd,\n\t\tCompletions: completions,\n\t\tAllCommands: toplevelCommandNames,\n\t})\n}\n\nfunc prepareFishCommands(binary string, parent *Command) []string {\n\tcommands := parent.Commands\n\tcompletions := []string{}\n\tfor _, command := range commands {\n\t\tif !command.Hidden {\n\t\t\tvar completion strings.Builder\n\t\t\tfmt.Fprintf(&completion,\n\t\t\t\t\"complete -x -c %s -n '%s' -a '%s'\",\n\t\t\t\tbinary,\n\t\t\t\tfishSubcommandHelper(binary, parent, commands),\n\t\t\t\tcommand.Name,\n\t\t\t)\n\n\t\t\tif command.Usage != \"\" {\n\t\t\t\tfmt.Fprintf(&completion,\n\t\t\t\t\t\" -d '%s'\",\n\t\t\t\t\tescapeSingleQuotes(command.Usage))\n\t\t\t}\n\t\t\tcompletions = append(completions, completion.String())\n\t\t}\n\n\t\tif command.ShellComplete != nil {\n\t\t\tvar completion strings.Builder\n\t\t\tvar path []string\n\t\t\tlineage := command.Lineage()\n\t\t\tfor i := len(lineage) - 2; i >= 0; i-- {\n\t\t\t\tpath = append(path, lineage[i].Name)\n\t\t\t}\n\n\t\t\tfmt.Fprintf(&completion,\n\t\t\t\t\"complete -c %s -n '%s' -xa '(%s %s %s 2>/dev/null)'\",\n\t\t\t\tbinary,\n\t\t\t\tfishFlagHelper(binary, command),\n\t\t\t\tbinary,\n\t\t\t\tstrings.Join(path, \" \"),\n\t\t\t\tcompletionFlag,\n\t\t\t)\n\t\t\tcompletions = append(completions, completion.String())\n\t\t}\n\n\t\tcompletions = append(\n\t\t\tcompletions,\n\t\t\tprepareFishFlags(binary, command)...,\n\t\t)\n\n\t\t// recursively iterate subcommands\n\t\tcompletions = append(\n\t\t\tcompletions,\n\t\t\tprepareFishCommands(binary, command)...,\n\t\t)\n\t}\n\n\treturn completions\n}\n\nfunc prepareFishFlags(binary string, owner *Command) []string {\n\tflags := owner.VisibleFlags()\n\tcompletions := []string{}\n\tfor _, f := range flags {\n\t\tcompletion := &strings.Builder{}\n\t\tfmt.Fprintf(completion,\n\t\t\t\"complete -c %s -n '%s'\",\n\t\t\tbinary,\n\t\t\tfishFlagHelper(binary, owner),\n\t\t)\n\n\t\tfishAddFileFlag(f, completion)\n\n\t\tfor idx, opt := range f.Names() {\n\t\t\tif idx == 0 {\n\t\t\t\tfmt.Fprintf(completion,\n\t\t\t\t\t\" -l %s\", strings.TrimSpace(opt),\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(completion,\n\t\t\t\t\t\" -s %s\", strings.TrimSpace(opt),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif flag, ok := f.(DocGenerationFlag); ok {\n\t\t\tif flag.TakesValue() {\n\t\t\t\tcompletion.WriteString(\" -r\")\n\t\t\t}\n\n\t\t\tif flag.GetUsage() != \"\" {\n\t\t\t\tfmt.Fprintf(completion,\n\t\t\t\t\t\" -d '%s'\",\n\t\t\t\t\tescapeSingleQuotes(flag.GetUsage()))\n\t\t\t}\n\t\t}\n\n\t\tcompletions = append(completions, completion.String())\n\t}\n\n\treturn completions\n}\n\nfunc fishAddFileFlag(flag Flag, completion *strings.Builder) {\n\tswitch f := flag.(type) {\n\tcase *StringFlag:\n\t\tif f.TakesFile {\n\t\t\treturn\n\t\t}\n\tcase *StringSliceFlag:\n\t\tif f.TakesFile {\n\t\t\treturn\n\t\t}\n\t}\n\tcompletion.WriteString(\" -f\")\n}\n\nfunc fishSubcommandHelper(binary string, command *Command, siblings []*Command) string {\n\tfishHelper := fmt.Sprintf(\"__fish_%s_no_subcommand\", binary)\n\tif len(command.Lineage()) > 1 {\n\t\tvar siblingNames []string\n\t\tfor _, sibling := range siblings {\n\t\t\tsiblingNames = append(siblingNames, sibling.Names()...)\n\t\t}\n\t\tancestry := commandAncestry(command)\n\t\tfishHelper = fmt.Sprintf(\n\t\t\t\"%s; and not __fish_seen_subcommand_from %s\",\n\t\t\tancestry,\n\t\t\tstrings.Join(siblingNames, \" \"),\n\t\t)\n\t}\n\treturn fishHelper\n}\n\nfunc fishFlagHelper(binary string, command *Command) string {\n\tfishHelper := fmt.Sprintf(\"__fish_%s_no_subcommand\", binary)\n\tif len(command.Lineage()) > 1 {\n\t\tfishHelper = commandAncestry(command)\n\t}\n\treturn fishHelper\n}\n\nfunc commandAncestry(command *Command) string {\n\tvar ancestry []string\n\tancestors := command.Lineage()\n\tfor i := len(ancestors) - 2; i >= 0; i-- {\n\t\tancestry = append(\n\t\t\tancestry,\n\t\t\tfmt.Sprintf(\n\t\t\t\t\"__fish_seen_subcommand_from %s\",\n\t\t\t\tstrings.Join(ancestors[i].Names(), \" \"),\n\t\t\t),\n\t\t)\n\t}\n\treturn strings.Join(ancestry, \"; and \")\n}\n\nfunc escapeSingleQuotes(input string) string {\n\treturn strings.ReplaceAll(input, `'`, `\\'`)\n}\n"
  },
  {
    "path": "fish_test.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFishCompletion(t *testing.T) {\n\t// Given\n\tcmd := buildExtendedTestCommand()\n\tcmd.Flags = append(cmd.Flags,\n\t\t&StringFlag{\n\t\t\tName:      \"logfile\",\n\t\t\tTakesFile: true,\n\t\t},\n\t\t&StringSliceFlag{\n\t\t\tName:      \"foofile\",\n\t\t\tTakesFile: true,\n\t\t})\n\tcmd.setupCommandGraph()\n\n\toldTemplate := FishCompletionTemplate\n\tdefer func() { FishCompletionTemplate = oldTemplate }()\n\tFishCompletionTemplate = \"{{something\"\n\n\t// test error case\n\t_, err1 := cmd.ToFishCompletion()\n\tassert.Error(t, err1)\n\n\t// reset the template\n\tFishCompletionTemplate = oldTemplate\n\t// When\n\tres, err := cmd.ToFishCompletion()\n\n\t// Then\n\trequire.NoError(t, err)\n\texpectFileContent(t, \"testdata/expected-fish-full.fish\", res)\n}\n\nfunc TestFishCompletionShellComplete(t *testing.T) {\n\tcmd := buildExtendedTestCommand()\n\tcmd.ShellComplete = func(context.Context, *Command) {}\n\n\tconfigCmd := cmd.Command(\"config\")\n\tconfigCmd.ShellComplete = func(context.Context, *Command) {}\n\n\tsubConfigCmd := configCmd.Command(\"sub-config\")\n\tsubConfigCmd.ShellComplete = func(context.Context, *Command) {}\n\n\tcmd.setupCommandGraph()\n\n\tres, err := cmd.ToFishCompletion()\n\trequire.NoError(t, err)\n\n\tassert.Contains(t, res, fmt.Sprintf(\"complete -c greet -n '__fish_greet_no_subcommand' -xa '(greet %s 2>/dev/null)'\", completionFlag))\n\tassert.Contains(t, res, fmt.Sprintf(\"complete -c greet -n '__fish_seen_subcommand_from config c' -xa '(greet config %s 2>/dev/null)'\", completionFlag))\n\tassert.Contains(t, res, fmt.Sprintf(\"complete -c greet -n '__fish_seen_subcommand_from config c; and __fish_seen_subcommand_from sub-config s ss' -xa '(greet config sub-config %s 2>/dev/null)'\", completionFlag))\n}\n"
  },
  {
    "path": "flag.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst defaultPlaceholder = \"value\"\n\nconst (\n\tdefaultSliceFlagSeparator       = \",\"\n\tdefaultMapFlagKeyValueSeparator = \"=\"\n\tdisableSliceFlagSeparator       = false\n)\n\nvar (\n\tslPfx = fmt.Sprintf(\"sl:::%d:::\", time.Now().UTC().UnixNano())\n\n\tcommaWhitespace = regexp.MustCompile(\"[, ]+.*\")\n)\n\n// GenerateShellCompletionFlag enables shell completion\nvar GenerateShellCompletionFlag Flag = &BoolFlag{\n\tName:   \"generate-shell-completion\",\n\tHidden: true,\n}\n\n// VersionFlag prints the version for the application\nvar VersionFlag Flag = &BoolFlag{\n\tName:        \"version\",\n\tAliases:     []string{\"v\"},\n\tUsage:       \"print the version\",\n\tHideDefault: true,\n\tLocal:       true,\n}\n\n// HelpFlag prints the help for all commands and subcommands.\n// Set to nil to disable the flag.  The subcommand\n// will still be added unless HideHelp or HideHelpCommand is set to true.\nvar HelpFlag Flag = &BoolFlag{\n\tName:        \"help\",\n\tAliases:     []string{\"h\"},\n\tUsage:       \"show help\",\n\tHideDefault: true,\n\tLocal:       true,\n}\n\n// FlagStringer converts a flag definition to a string. This is used by help\n// to display a flag.\nvar FlagStringer FlagStringFunc = stringifyFlag\n\n// Serializer is used to circumvent the limitations of flag.FlagSet.Set\ntype Serializer interface {\n\tSerialize() string\n}\n\n// FlagNamePrefixer converts a full flag name and its placeholder into the help\n// message flag prefix. This is used by the default FlagStringer.\nvar FlagNamePrefixer FlagNamePrefixFunc = prefixedNames\n\n// FlagEnvHinter annotates flag help message with the environment variable\n// details. This is used by the default FlagStringer.\nvar FlagEnvHinter FlagEnvHintFunc = withEnvHint\n\n// FlagFileHinter annotates flag help message with the environment variable\n// details. This is used by the default FlagStringer.\nvar FlagFileHinter FlagFileHintFunc = withFileHint\n\n// FlagsByName is a slice of Flag.\ntype FlagsByName []Flag\n\nfunc (f FlagsByName) Len() int {\n\treturn len(f)\n}\n\nfunc (f FlagsByName) Less(i, j int) bool {\n\treturn lexicographicLess(f[i].Names()[0], f[j].Names()[0])\n}\n\nfunc (f FlagsByName) Swap(i, j int) {\n\tf[i], f[j] = f[j], f[i]\n}\n\n// ActionableFlag is an interface that wraps Flag interface and RunAction operation.\ntype ActionableFlag interface {\n\tRunAction(context.Context, *Command) error\n}\n\n// Flag is a common interface related to parsing flags in cli.\n// For more advanced flag parsing techniques, it is recommended that\n// this interface be implemented.\ntype Flag interface {\n\tfmt.Stringer\n\n\t// Retrieve the value of the Flag\n\tGet() any\n\n\t// Lifecycle methods.\n\t// flag callback prior to parsing\n\tPreParse() error\n\n\t// flag callback post parsing\n\tPostParse() error\n\n\t// Apply Flag settings to the given flag set\n\tSet(string, string) error\n\n\t// All possible names for this flag\n\tNames() []string\n\n\t// Whether the flag has been set or not\n\tIsSet() bool\n}\n\n// RequiredFlag is an interface that allows us to mark flags as required\n// it allows flags required flags to be backwards compatible with the Flag interface\ntype RequiredFlag interface {\n\t// whether the flag is a required flag or not\n\tIsRequired() bool\n}\n\n// DocGenerationFlag is an interface that allows documentation generation for the flag\ntype DocGenerationFlag interface {\n\t// TakesValue returns true if the flag takes a value, otherwise false\n\tTakesValue() bool\n\n\t// GetUsage returns the usage string for the flag\n\tGetUsage() string\n\n\t// GetValue returns the flags value as string representation and an empty\n\t// string if the flag takes no value at all.\n\tGetValue() string\n\n\t// GetDefaultText returns the default text for this flag\n\tGetDefaultText() string\n\n\t// GetEnvVars returns the env vars for this flag\n\tGetEnvVars() []string\n\n\t// IsDefaultVisible returns whether the default value should be shown in\n\t// help text\n\tIsDefaultVisible() bool\n\t// TypeName to detect if a flag is a string, bool, etc.\n\tTypeName() string\n}\n\n// DocGenerationMultiValueFlag extends DocGenerationFlag for slice/map based flags.\ntype DocGenerationMultiValueFlag interface {\n\tDocGenerationFlag\n\n\t// IsMultiValueFlag returns true for flags that can be given multiple times.\n\tIsMultiValueFlag() bool\n}\n\n// Countable is an interface to enable detection of flag values which support\n// repetitive flags\ntype Countable interface {\n\tCount() int\n}\n\n// VisibleFlag is an interface that allows to check if a flag is visible\ntype VisibleFlag interface {\n\t// IsVisible returns true if the flag is not hidden, otherwise false\n\tIsVisible() bool\n}\n\n// CategorizableFlag is an interface that allows us to potentially\n// use a flag in a categorized representation.\ntype CategorizableFlag interface {\n\t// Returns the category of the flag\n\tGetCategory() string\n\n\t// Sets the category of the flag\n\tSetCategory(string)\n}\n\n// LocalFlag is an interface to enable detection of flags which are local\n// to current command\ntype LocalFlag interface {\n\tIsLocal() bool\n}\n\nfunc visibleFlags(fl []Flag) []Flag {\n\tvar visible []Flag\n\tfor _, f := range fl {\n\t\tif vf, ok := f.(VisibleFlag); ok && vf.IsVisible() {\n\t\t\tvisible = append(visible, f)\n\t\t}\n\t}\n\treturn visible\n}\n\nfunc FlagNames(name string, aliases []string) []string {\n\tvar ret []string\n\n\tfor _, part := range append([]string{name}, aliases...) {\n\t\t// v1 -> v2 migration warning zone:\n\t\t// Strip off anything after the first found comma or space, which\n\t\t// *hopefully* makes it a tiny bit more obvious that unexpected behavior is\n\t\t// caused by using the v1 form of stringly typed \"Name\".\n\t\tret = append(ret, commaWhitespace.ReplaceAllString(part, \"\"))\n\t}\n\n\treturn ret\n}\n\nfunc hasFlag(flags []Flag, fl Flag) bool {\n\tfor _, existing := range flags {\n\t\tif fl == existing {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc flagSplitMultiValues(val string, sliceSeparator string, disableSliceSeparator bool) []string {\n\tif disableSliceSeparator {\n\t\treturn []string{val}\n\t}\n\n\tif len(sliceSeparator) == 0 {\n\t\tsliceSeparator = defaultSliceFlagSeparator\n\t}\n\treturn strings.Split(val, sliceSeparator)\n}\n"
  },
  {
    "path": "flag_bool.go",
    "content": "package cli\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\ntype BoolFlag = FlagBase[bool, BoolConfig, boolValue]\n\n// BoolConfig defines the configuration for bool flags\ntype BoolConfig struct {\n\tCount *int\n}\n\n// boolValue needs to implement the boolFlag internal interface in flag\n// to be able to capture bool fields and values\n//\n//\ttype boolFlag interface {\n//\t\t  Value\n//\t\t  IsBoolFlag() bool\n//\t}\ntype boolValue struct {\n\tdestination *bool\n\tcount       *int\n}\n\nfunc (cmd *Command) Bool(name string) bool {\n\tif v, ok := cmd.Value(name).(bool); ok {\n\t\ttracef(\"bool available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"bool NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn false\n}\n\n// Below functions are to satisfy the ValueCreator interface\n\n// Create creates the bool value\nfunc (b boolValue) Create(val bool, p *bool, c BoolConfig) Value {\n\t*p = val\n\tif c.Count == nil {\n\t\tc.Count = new(int)\n\t}\n\treturn &boolValue{\n\t\tdestination: p,\n\t\tcount:       c.Count,\n\t}\n}\n\n// ToString formats the bool value\nfunc (b boolValue) ToString(value bool) string {\n\tb.destination = &value\n\treturn b.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (b *boolValue) Set(s string) error {\n\tv, err := strconv.ParseBool(s)\n\tif err != nil {\n\t\terr = errors.New(\"parse error\")\n\t\treturn err\n\t}\n\t*b.destination = v\n\tif b.count != nil {\n\t\t*b.count = *b.count + 1\n\t}\n\treturn err\n}\n\nfunc (b *boolValue) Get() interface{} { return *b.destination }\n\nfunc (b *boolValue) String() string {\n\treturn strconv.FormatBool(*b.destination)\n}\n\nfunc (b *boolValue) IsBoolFlag() bool { return true }\n"
  },
  {
    "path": "flag_bool_with_inverse.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n)\n\nvar DefaultInverseBoolPrefix = \"no-\"\n\ntype BoolWithInverseFlag struct {\n\tName             string                                      `json:\"name\"`             // name of the flag\n\tCategory         string                                      `json:\"category\"`         // category of the flag, if any\n\tDefaultText      string                                      `json:\"defaultText\"`      // default text of the flag for usage purposes\n\tHideDefault      bool                                        `json:\"hideDefault\"`      // whether to hide the default value in output\n\tUsage            string                                      `json:\"usage\"`            // usage string for help output\n\tSources          ValueSourceChain                            `json:\"-\"`                // sources to load flag value from\n\tRequired         bool                                        `json:\"required\"`         // whether the flag is required or not\n\tHidden           bool                                        `json:\"hidden\"`           // whether to hide the flag in help output\n\tLocal            bool                                        `json:\"local\"`            // whether the flag needs to be applied to subcommands as well\n\tValue            bool                                        `json:\"defaultValue\"`     // default value for this flag if not set by from any source\n\tDestination      *bool                                       `json:\"-\"`                // destination pointer for value when set\n\tAliases          []string                                    `json:\"aliases\"`          // Aliases that are allowed for this flag\n\tTakesFile        bool                                        `json:\"takesFileArg\"`     // whether this flag takes a file argument, mainly for shell completion purposes\n\tAction           func(context.Context, *Command, bool) error `json:\"-\"`                // Action callback to be called when flag is set\n\tOnlyOnce         bool                                        `json:\"onlyOnce\"`         // whether this flag can be duplicated on the command line\n\tValidator        func(bool) error                            `json:\"-\"`                // custom function to validate this flag value\n\tValidateDefaults bool                                        `json:\"validateDefaults\"` // whether to validate defaults or not\n\tConfig           BoolConfig                                  `json:\"config\"`           // Additional/Custom configuration associated with this flag type\n\tInversePrefix    string                                      `json:\"invPrefix\"`        // The prefix used to indicate a negative value. Default: `env` becomes `no-env`\n\n\t// unexported fields for internal use\n\tcount      int   // number of times the flag has been set\n\thasBeenSet bool  // whether the flag has been set from env or file\n\tapplied    bool  // whether the flag has been applied to a flag set already\n\tvalue      Value // value representing this flag's value\n\tpset       bool\n\tnset       bool\n}\n\nfunc (bif *BoolWithInverseFlag) IsSet() bool {\n\treturn bif.hasBeenSet\n}\n\nfunc (bif *BoolWithInverseFlag) Get() any {\n\treturn bif.value.Get()\n}\n\nfunc (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error {\n\tif bif.Action != nil {\n\t\treturn bif.Action(ctx, cmd, bif.Get().(bool))\n\t}\n\n\treturn nil\n}\n\nfunc (bif *BoolWithInverseFlag) IsLocal() bool {\n\treturn bif.Local\n}\n\nfunc (bif *BoolWithInverseFlag) inversePrefix() string {\n\tif bif.InversePrefix == \"\" {\n\t\tbif.InversePrefix = DefaultInverseBoolPrefix\n\t}\n\n\treturn bif.InversePrefix\n}\n\nfunc (bif *BoolWithInverseFlag) PreParse() error {\n\tcount := bif.Config.Count\n\tif count == nil {\n\t\tcount = &bif.count\n\t}\n\tdest := bif.Destination\n\tif dest == nil {\n\t\tdest = new(bool)\n\t}\n\t*dest = bif.Value\n\tbif.value = &boolValue{\n\t\tdestination: dest,\n\t\tcount:       count,\n\t}\n\n\t// Validate the given default or values set from external sources as well\n\tif bif.Validator != nil && bif.ValidateDefaults {\n\t\tif err := bif.Validator(bif.value.Get().(bool)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tbif.applied = true\n\treturn nil\n}\n\nfunc (bif *BoolWithInverseFlag) PostParse() error {\n\ttracef(\"postparse (flag=%[1]q)\", bif.Name)\n\n\tif !bif.hasBeenSet {\n\t\tif val, source, found := bif.Sources.LookupWithSource(); found {\n\t\t\tif val == \"\" {\n\t\t\t\tval = \"false\"\n\t\t\t}\n\t\t\tif err := bif.Set(bif.Name, val); err != nil {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s\",\n\t\t\t\t\tval, bif.Value, source, bif.Name, err,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tbif.hasBeenSet = true\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (bif *BoolWithInverseFlag) Set(name, val string) error {\n\tif bif.count > 0 && bif.OnlyOnce {\n\t\treturn fmt.Errorf(\"cant duplicate this flag\")\n\t}\n\n\tbif.hasBeenSet = true\n\n\tif slices.Contains(append([]string{bif.Name}, bif.Aliases...), name) {\n\t\tif bif.nset {\n\t\t\treturn fmt.Errorf(\"cannot set both flags `--%s` and `--%s`\", bif.Name, bif.inversePrefix()+bif.Name)\n\t\t}\n\t\tif err := bif.value.Set(val); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbif.pset = true\n\t} else {\n\t\tif bif.pset {\n\t\t\treturn fmt.Errorf(\"cannot set both flags `--%s` and `--%s`\", bif.Name, bif.inversePrefix()+bif.Name)\n\t\t}\n\t\tif err := bif.value.Set(\"false\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbif.nset = true\n\t}\n\n\tif bif.Validator != nil {\n\t\treturn bif.Validator(bif.value.Get().(bool))\n\t}\n\treturn nil\n}\n\nfunc (bif *BoolWithInverseFlag) Names() []string {\n\tnames := append([]string{bif.Name}, bif.Aliases...)\n\n\tfor _, name := range names {\n\t\tnames = append(names, bif.inversePrefix()+name)\n\t}\n\n\treturn names\n}\n\nfunc (bif *BoolWithInverseFlag) IsRequired() bool {\n\treturn bif.Required\n}\n\nfunc (bif *BoolWithInverseFlag) IsVisible() bool {\n\treturn !bif.Hidden\n}\n\n// String implements the standard Stringer interface.\n//\n// Example for BoolFlag{Name: \"env\"}\n// --[no-]env\t(default: false)\nfunc (bif *BoolWithInverseFlag) String() string {\n\tout := FlagStringer(bif)\n\n\ti := strings.Index(out, \"\\t\")\n\n\tprefix := \"--\"\n\n\t// single character flags are prefixed with `-` instead of `--`\n\tif len(bif.Name) == 1 {\n\t\tprefix = \"-\"\n\t}\n\n\treturn fmt.Sprintf(\"%s[%s]%s%s\", prefix, bif.inversePrefix(), bif.Name, out[i:])\n}\n\n// IsBoolFlag returns whether the flag doesnt need to accept args\nfunc (bif *BoolWithInverseFlag) IsBoolFlag() bool {\n\treturn true\n}\n\n// Count returns the number of times this flag has been invoked\nfunc (bif *BoolWithInverseFlag) Count() int {\n\treturn bif.count\n}\n\n// GetDefaultText returns the default text for this flag\nfunc (bif *BoolWithInverseFlag) GetDefaultText() string {\n\tif bif.Required {\n\t\treturn bif.DefaultText\n\t}\n\treturn boolValue{}.ToString(bif.Value)\n}\n\n// GetCategory returns the category of the flag\nfunc (bif *BoolWithInverseFlag) GetCategory() string {\n\treturn bif.Category\n}\n\nfunc (bif *BoolWithInverseFlag) SetCategory(c string) {\n\tbif.Category = c\n}\n\n// GetUsage returns the usage string for the flag\nfunc (bif *BoolWithInverseFlag) GetUsage() string {\n\treturn bif.Usage\n}\n\n// GetEnvVars returns the env vars for this flag\nfunc (bif *BoolWithInverseFlag) GetEnvVars() []string {\n\treturn bif.Sources.EnvKeys()\n}\n\n// GetValue returns the flags value as string representation and an empty\n// string if the flag takes no value at all.\nfunc (bif *BoolWithInverseFlag) GetValue() string {\n\treturn \"\"\n}\n\nfunc (bif *BoolWithInverseFlag) TakesValue() bool {\n\treturn false\n}\n\n// IsDefaultVisible returns true if the flag is not hidden, otherwise false\nfunc (bif *BoolWithInverseFlag) IsDefaultVisible() bool {\n\treturn !bif.HideDefault\n}\n\n// TypeName is used for stringify/docs. For bool its a no-op\nfunc (bif *BoolWithInverseFlag) TypeName() string {\n\treturn \"bool\"\n}\n"
  },
  {
    "path": "flag_bool_with_inverse_test.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar errBothEnvFlagsAreSet = fmt.Errorf(\"cannot set both flags `--env` and `--no-env`\")\n\ntype boolWithInverseTestCase struct {\n\targs    []string\n\ttoBeSet bool\n\tvalue   bool\n\terr     error\n\tenvVars map[string]string\n}\n\nfunc (tc *boolWithInverseTestCase) Run(t *testing.T, flagWithInverse *BoolWithInverseFlag) error {\n\tcmd := &Command{\n\t\tFlags:  []Flag{flagWithInverse},\n\t\tAction: func(context.Context, *Command) error { return nil },\n\t}\n\n\tfor key, val := range tc.envVars {\n\t\tt.Setenv(key, val)\n\t}\n\n\terr := cmd.Run(buildTestContext(t), append([]string{\"prog\"}, tc.args...))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif flagWithInverse.IsSet() != tc.toBeSet {\n\t\treturn fmt.Errorf(\"flag should be set %t, but got %t\", tc.toBeSet, flagWithInverse.IsSet())\n\t}\n\n\tif flagWithInverse.Get() != tc.value {\n\t\treturn fmt.Errorf(\"flag value should be %t, but got %t\", tc.value, flagWithInverse.Get())\n\t}\n\n\treturn nil\n}\n\nfunc runBoolWithInverseFlagTests(t *testing.T, newFlagMethod func() *BoolWithInverseFlag, cases []*boolWithInverseTestCase) error {\n\tfor _, tc := range cases {\n\t\tt.Run(strings.Join(tc.args, \" \")+fmt.Sprintf(\"%[1]v %[2]v %[3]v\", tc.value, tc.toBeSet, tc.err), func(t *testing.T) {\n\t\t\tr := require.New(t)\n\n\t\t\tfl := newFlagMethod()\n\n\t\t\terr := tc.Run(t, fl)\n\t\t\tif err != nil && tc.err == nil {\n\t\t\t\tr.NoError(err)\n\t\t\t}\n\n\t\t\tif err == nil && tc.err != nil {\n\t\t\t\tr.Error(err)\n\t\t\t}\n\n\t\t\tif err != nil && tc.err != nil {\n\t\t\t\tr.ErrorContains(err, tc.err.Error())\n\t\t\t}\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc TestBoolWithInverseBasic(t *testing.T) {\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\treturn &BoolWithInverseFlag{\n\t\t\tName: \"env\",\n\t\t}\n\t}\n\n\ttestCases := []*boolWithInverseTestCase{\n\t\t{\n\t\t\targs:    []string{\"--no-env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs:    []string{\"--env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   true,\n\t\t},\n\t\t{\n\t\t\ttoBeSet: false,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs: []string{\"--env\", \"--no-env\"},\n\t\t\terr:  errBothEnvFlagsAreSet,\n\t\t},\n\t}\n\n\terr := runBoolWithInverseFlagTests(t, flagMethod, testCases)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseAction(t *testing.T) {\n\terr := fmt.Errorf(\"action called\")\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\tbif := &BoolWithInverseFlag{\n\t\t\tName: \"env\",\n\n\t\t\t// Setting env to the opposite to test flag Action is working as intended\n\t\t\tAction: func(_ context.Context, cmd *Command, value bool) error {\n\t\t\t\treturn err\n\t\t\t},\n\t\t}\n\t\treturn bif\n\t}\n\n\ttestCases := []*boolWithInverseTestCase{\n\t\t{\n\t\t\targs:    []string{\"--no-env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t\terr:     err,\n\t\t},\n\t\t{\n\t\t\targs:    []string{\"--env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   true,\n\t\t\terr:     err,\n\t\t},\n\n\t\t// This test is not inverse because the flag action is never called\n\t\t{\n\t\t\ttoBeSet: false,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs: []string{\"--env\", \"--no-env\"},\n\t\t\terr:  errBothEnvFlagsAreSet,\n\t\t},\n\t}\n\n\terrr := runBoolWithInverseFlagTests(t, flagMethod, testCases)\n\tif errr != nil {\n\t\tt.Error(errr)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseAlias(t *testing.T) {\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\treturn &BoolWithInverseFlag{\n\t\t\tName:    \"env\",\n\t\t\tAliases: []string{\"e\", \"do-env\"},\n\t\t}\n\t}\n\n\ttestCases := []*boolWithInverseTestCase{\n\t\t{\n\t\t\targs:    []string{\"--no-e\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs:    []string{\"--e\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   true,\n\t\t},\n\t\t{\n\t\t\ttoBeSet: false,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs: []string{\"--do-env\", \"--no-do-env\"},\n\t\t\terr:  errBothEnvFlagsAreSet,\n\t\t},\n\t}\n\n\terr := runBoolWithInverseFlagTests(t, flagMethod, testCases)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseEnvVars(t *testing.T) {\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\treturn &BoolWithInverseFlag{\n\t\t\tName:    \"env\",\n\t\t\tSources: EnvVars(\"ENV\", \"NO-ENV\"),\n\t\t\tLocal:   true,\n\t\t}\n\t}\n\n\ttestCases := []*boolWithInverseTestCase{\n\t\t{\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"NO-ENV\": \"false\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   true,\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"ENV\": \"true\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"ENV\": \"false\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttoBeSet: false,\n\t\t\tvalue:   false,\n\t\t},\n\t\t// TODO\n\t\t/*{\n\t\t\terr: errBothEnvFlagsAreSet,\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"ENV\":    \"true\",\n\t\t\t\t\"NO-ENV\": \"true\",\n\t\t\t},\n\t\t},*/\n\t\t{\n\t\t\terr: fmt.Errorf(\"could not parse \\\"true_env\\\" as bool value from environment variable \\\"ENV\\\" for flag env: parse error\"),\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"ENV\": \"true_env\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\terr: fmt.Errorf(\"could not parse \\\"false_env\\\" as bool value from environment variable \\\"NO-ENV\\\" for flag env: parse error\"),\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"NO-ENV\": \"false_env\",\n\t\t\t},\n\t\t},\n\t}\n\n\terr := runBoolWithInverseFlagTests(t, flagMethod, testCases)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseWithPrefix(t *testing.T) {\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\treturn &BoolWithInverseFlag{\n\t\t\tName:          \"env\",\n\t\t\tInversePrefix: \"without-\",\n\t\t}\n\t}\n\n\ttestCases := []*boolWithInverseTestCase{\n\t\t{\n\t\t\targs:    []string{\"--without-env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs:    []string{\"--env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   true,\n\t\t},\n\t\t{\n\t\t\ttoBeSet: false,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs: []string{\"--env\", \"--without-env\"},\n\t\t\terr:  fmt.Errorf(\"cannot set both flags `--env` and `--without-env`\"),\n\t\t},\n\t\t{\n\t\t\targs: []string{\"--without-env\", \"--env\"},\n\t\t\terr:  fmt.Errorf(\"cannot set both flags `--env` and `--without-env`\"),\n\t\t},\n\t}\n\n\terr := runBoolWithInverseFlagTests(t, flagMethod, testCases)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseRequired(t *testing.T) {\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\treturn &BoolWithInverseFlag{\n\t\t\tName:     \"env\",\n\t\t\tRequired: true,\n\t\t}\n\t}\n\n\ttestCases := []*boolWithInverseTestCase{\n\t\t{\n\t\t\targs:    []string{\"--no-env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   false,\n\t\t},\n\t\t{\n\t\t\targs:    []string{\"--env\"},\n\t\t\ttoBeSet: true,\n\t\t\tvalue:   true,\n\t\t},\n\t\t{\n\t\t\targs: []string{\"--env\", \"--no-env\"},\n\t\t\terr:  errBothEnvFlagsAreSet,\n\t\t},\n\t}\n\n\terr := runBoolWithInverseFlagTests(t, flagMethod, testCases)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseNames(t *testing.T) {\n\tflag := &BoolWithInverseFlag{\n\t\tName:     \"env\",\n\t\tRequired: true,\n\t}\n\tnames := flag.Names()\n\n\trequire.Len(t, names, 2)\n\trequire.Equal(t, \"env\", names[0], \"expected first name to be `env`\")\n\trequire.Equal(t, \"no-env\", names[1], \"expected first name to be `no-env`\")\n\n\tvar d DocGenerationFlag = flag\n\trequire.Equal(t, \"bool\", d.TypeName())\n}\n\nfunc TestBoolWithInverseString(t *testing.T) {\n\ttcs := []struct {\n\t\ttestName      string\n\t\tflagName      string\n\t\trequired      bool\n\t\tusage         string\n\t\tinversePrefix string\n\t\texpected      string\n\t}{\n\t\t{\n\t\t\ttestName: \"empty inverse prefix no flag\",\n\t\t\tflagName: \"\",\n\t\t\trequired: true,\n\t\t\texpected: \"--[no-]\\t\",\n\t\t},\n\t\t{\n\t\t\ttestName: \"single-char flag name\",\n\t\t\tflagName: \"e\",\n\t\t\trequired: true,\n\t\t\texpected: \"-[no-]e\\t\",\n\t\t},\n\t\t{\n\t\t\ttestName: \"multi-char flag name\",\n\t\t\tflagName: \"env\",\n\t\t\trequired: true,\n\t\t\texpected: \"--[no-]env\\t\",\n\t\t},\n\t\t{\n\t\t\ttestName: \"required with usage\",\n\t\t\tflagName: \"env\",\n\t\t\trequired: true,\n\t\t\tusage:    \"env usage\",\n\t\t\texpected: \"--[no-]env\\tenv usage\",\n\t\t},\n\t\t{\n\t\t\ttestName: \"required without usage\",\n\t\t\tflagName: \"env\",\n\t\t\trequired: true,\n\t\t\texpected: \"--[no-]env\\t\",\n\t\t},\n\t\t{\n\t\t\ttestName: \"not required with default usage\",\n\t\t\tflagName: \"env\",\n\t\t\trequired: false,\n\t\t\texpected: \"--[no-]env\\t(default: false)\",\n\t\t},\n\t\t{\n\t\t\ttestName:      \"custom inverse prefix\",\n\t\t\tflagName:      \"env\",\n\t\t\trequired:      true,\n\t\t\tinversePrefix: \"nope-\",\n\t\t\texpected:      \"--[nope-]env\\t\",\n\t\t},\n\t\t{\n\t\t\ttestName: \"empty inverse prefix\",\n\t\t\tflagName: \"env\",\n\t\t\trequired: true,\n\t\t\texpected: \"--[no-]env\\t\",\n\t\t},\n\t}\n\n\tfor _, tc := range tcs {\n\t\tt.Run(tc.testName, func(t *testing.T) {\n\t\t\tflag := &BoolWithInverseFlag{\n\t\t\t\tName:          tc.flagName,\n\t\t\t\tUsage:         tc.usage,\n\t\t\t\tRequired:      tc.required,\n\t\t\t\tInversePrefix: tc.inversePrefix,\n\t\t\t}\n\n\t\t\trequire.Equal(t, tc.expected, flag.String())\n\t\t})\n\t}\n}\n\nfunc TestBoolWithInverseDestination(t *testing.T) {\n\tdestination := new(bool)\n\tcount := new(int)\n\n\tflagMethod := func() *BoolWithInverseFlag {\n\t\treturn &BoolWithInverseFlag{\n\t\t\tName:        \"env\",\n\t\t\tDestination: destination,\n\t\t\tConfig: BoolConfig{\n\t\t\t\tCount: count,\n\t\t\t},\n\t\t}\n\t}\n\n\tcheckAndReset := func(expectedCount int, expectedValue bool) error {\n\t\tif *count != expectedCount {\n\t\t\treturn fmt.Errorf(\"expected count to be %d, got %d\", expectedCount, *count)\n\t\t}\n\n\t\tif *destination != expectedValue {\n\t\t\treturn fmt.Errorf(\"expected destination to be %t, got %t\", expectedValue, *destination)\n\t\t}\n\n\t\t*count = 0\n\t\t*destination = false\n\n\t\treturn nil\n\t}\n\n\terr := (&boolWithInverseTestCase{\n\t\targs:    []string{\"--env\"},\n\t\ttoBeSet: true,\n\t\tvalue:   true,\n\t}).Run(t, flagMethod())\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = checkAndReset(1, true)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = (&boolWithInverseTestCase{\n\t\targs:    []string{\"--no-env\"},\n\t\ttoBeSet: true,\n\t\tvalue:   false,\n\t}).Run(t, flagMethod())\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = checkAndReset(1, false)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = (&boolWithInverseTestCase{\n\t\targs:    []string{},\n\t\ttoBeSet: false,\n\t\tvalue:   false,\n\t}).Run(t, flagMethod())\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = checkAndReset(0, false)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tf := flagMethod()\n\tf.Value = true\n\terr = (&boolWithInverseTestCase{\n\t\targs:    []string{},\n\t\ttoBeSet: false,\n\t\tvalue:   true,\n\t}).Run(t, f)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = checkAndReset(0, true)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBoolWithInverseFlag_SatisfiesRequiredFlagInterface(t *testing.T) {\n\tvar f RequiredFlag = &BoolWithInverseFlag{}\n\n\t_ = f.IsRequired()\n}\n\nfunc TestBoolWithInverseFlag_SatisfiesVisibleFlagInterface(t *testing.T) {\n\tvar f VisibleFlag = &BoolWithInverseFlag{}\n\n\t_ = f.IsVisible()\n}\n"
  },
  {
    "path": "flag_duration.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype DurationFlag = FlagBase[time.Duration, NoConfig, durationValue]\n\n// -- time.Duration Value\ntype durationValue time.Duration\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (d durationValue) Create(val time.Duration, p *time.Duration, c NoConfig) Value {\n\t*p = val\n\treturn (*durationValue)(p)\n}\n\nfunc (d durationValue) ToString(val time.Duration) string {\n\td = durationValue(val)\n\treturn d.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (d *durationValue) Set(s string) error {\n\tv, err := time.ParseDuration(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*d = durationValue(v)\n\treturn err\n}\n\nfunc (d *durationValue) Get() any { return time.Duration(*d) }\n\nfunc (d *durationValue) String() string {\n\treturn fmt.Sprintf(\"%v\", time.Duration(*d))\n}\n\nfunc (cmd *Command) Duration(name string) time.Duration {\n\tif v, ok := cmd.Value(name).(time.Duration); ok {\n\t\ttracef(\"duration available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"duration NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn 0\n}\n"
  },
  {
    "path": "flag_ext.go",
    "content": "package cli\n\nimport \"flag\"\n\ntype extFlag struct {\n\tf *flag.Flag\n}\n\nfunc (e *extFlag) PreParse() error {\n\tif e.f.DefValue != \"\" {\n\t\treturn e.Set(\"\", e.f.DefValue)\n\t}\n\n\treturn nil\n}\n\nfunc (e *extFlag) PostParse() error {\n\treturn nil\n}\n\nfunc (e *extFlag) Set(_ string, val string) error {\n\treturn e.f.Value.Set(val)\n}\n\nfunc (e *extFlag) Get() any {\n\treturn e.f.Value.(flag.Getter).Get()\n}\n\nfunc (e *extFlag) Names() []string {\n\treturn []string{e.f.Name}\n}\n\nfunc (e *extFlag) IsSet() bool {\n\treturn false\n}\n\nfunc (e *extFlag) String() string {\n\treturn FlagStringer(e)\n}\n\nfunc (e *extFlag) IsVisible() bool {\n\treturn true\n}\n\nfunc (e *extFlag) TakesValue() bool {\n\treturn false\n}\n\nfunc (e *extFlag) GetUsage() string {\n\treturn e.f.Usage\n}\n\nfunc (e *extFlag) GetValue() string {\n\treturn e.f.Value.String()\n}\n\nfunc (e *extFlag) GetDefaultText() string {\n\treturn e.f.DefValue\n}\n\nfunc (e *extFlag) GetEnvVars() []string {\n\treturn nil\n}\n"
  },
  {
    "path": "flag_float.go",
    "content": "package cli\n\nimport (\n\t\"strconv\"\n\t\"unsafe\"\n)\n\ntype (\n\tFloatFlag   = FlagBase[float64, NoConfig, floatValue[float64]]\n\tFloat32Flag = FlagBase[float32, NoConfig, floatValue[float32]]\n\tFloat64Flag = FlagBase[float64, NoConfig, floatValue[float64]]\n)\n\n// -- float Value\ntype floatValue[T float32 | float64] struct {\n\tval *T\n}\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (f floatValue[T]) Create(val T, p *T, c NoConfig) Value {\n\t*p = val\n\n\treturn &floatValue[T]{val: p}\n}\n\nfunc (f floatValue[T]) ToString(b T) string {\n\tf.val = &b\n\treturn f.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (f *floatValue[T]) Set(s string) error {\n\tv, err := strconv.ParseFloat(s, int(unsafe.Sizeof(T(0))*8))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*f.val = T(v)\n\treturn nil\n}\n\nfunc (f *floatValue[T]) Get() any { return *f.val }\n\nfunc (f *floatValue[T]) String() string {\n\treturn strconv.FormatFloat(float64(*f.val), 'g', -1, int(unsafe.Sizeof(T(0))*8))\n}\n\n// Float looks up the value of a local FloatFlag, returns\n// 0 if not found\nfunc (cmd *Command) Float(name string) float64 {\n\treturn getFloat[float64](cmd, name)\n}\n\n// Float32 looks up the value of a local Float32Flag, returns\n// 0 if not found\nfunc (cmd *Command) Float32(name string) float32 {\n\treturn getFloat[float32](cmd, name)\n}\n\n// Float64 looks up the value of a local Float64Flag, returns\n// 0 if not found\nfunc (cmd *Command) Float64(name string) float64 {\n\treturn getFloat[float64](cmd, name)\n}\n\nfunc getFloat[T float32 | float64](cmd *Command, name string) T {\n\tif v, ok := cmd.Value(name).(T); ok {\n\t\ttracef(\"float available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\n\t\treturn v\n\t}\n\n\ttracef(\"float NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn 0\n}\n"
  },
  {
    "path": "flag_float_slice.go",
    "content": "package cli\n\ntype (\n\tFloatSlice       = SliceBase[float64, NoConfig, floatValue[float64]]\n\tFloat32Slice     = SliceBase[float32, NoConfig, floatValue[float32]]\n\tFloat64Slice     = SliceBase[float64, NoConfig, floatValue[float64]]\n\tFloatSliceFlag   = FlagBase[[]float64, NoConfig, FloatSlice]\n\tFloat32SliceFlag = FlagBase[[]float32, NoConfig, Float32Slice]\n\tFloat64SliceFlag = FlagBase[[]float64, NoConfig, Float64Slice]\n)\n\nvar (\n\tNewFloatSlice   = NewSliceBase[float64, NoConfig, floatValue[float64]]\n\tNewFloat32Slice = NewSliceBase[float32, NoConfig, floatValue[float32]]\n\tNewFloat64Slice = NewSliceBase[float64, NoConfig, floatValue[float64]]\n)\n\n// FloatSlice looks up the value of a local FloatSliceFlag, returns\n// nil if not found\nfunc (cmd *Command) FloatSlice(name string) []float64 {\n\treturn getNumberSlice[float64](cmd, name)\n}\n\n// Float32Slice looks up the value of a local Float32Slice, returns\n// nil if not found\nfunc (cmd *Command) Float32Slice(name string) []float32 {\n\treturn getNumberSlice[float32](cmd, name)\n}\n\n// Float64Slice looks up the value of a local Float64SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Float64Slice(name string) []float64 {\n\treturn getNumberSlice[float64](cmd, name)\n}\n"
  },
  {
    "path": "flag_float_slice_test.go",
    "content": "package cli\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCommand_FloatSlice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []float64\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &FloatSliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []float64{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &FloatSliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []float64{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.FloatSlice(name), \"FloatSlice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Float32Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []float32\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Float32SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []float32{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Float32SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []float32{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Float32Slice(name), \"Float32Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Float64Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []float64\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Float64SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []float64{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Float64SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []float64{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Float64Slice(name), \"Float64Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "flag_float_test.go",
    "content": "package cli\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_FloatFlag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue float64\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &FloatFlag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"-234567\"},\n\t\t\texpectedValue: -234567,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &FloatFlag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Float(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_Float32Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue float32\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Float32Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"2147483647\"},\n\t\t\texpectedValue: 2147483647,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Float32Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Float32(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_Float64Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue float64\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Float64Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"-2147483648\"},\n\t\t\texpectedValue: -2147483648,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Float64Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Float64(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_floatValue_String(t *testing.T) {\n\tvar f float64 = 100\n\tfv := floatValue[float64]{val: &f}\n\n\tassert.Equal(t, \"100\", fv.String())\n}\n"
  },
  {
    "path": "flag_generic.go",
    "content": "package cli\n\ntype GenericFlag = FlagBase[Value, NoConfig, genericValue]\n\n// -- Value Value\ntype genericValue struct {\n\tval Value\n}\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (f genericValue) Create(val Value, p *Value, c NoConfig) Value {\n\t*p = val\n\treturn &genericValue{\n\t\tval: *p,\n\t}\n}\n\nfunc (f genericValue) ToString(b Value) string {\n\tf.val = b\n\treturn f.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (f *genericValue) Set(s string) error {\n\tif f.val != nil {\n\t\treturn f.val.Set(s)\n\t}\n\treturn nil\n}\n\nfunc (f *genericValue) Get() any {\n\tif f.val != nil {\n\t\treturn f.val.Get()\n\t}\n\treturn nil\n}\n\nfunc (f *genericValue) String() string {\n\tif f.val != nil {\n\t\treturn f.val.String()\n\t}\n\treturn \"\"\n}\n\nfunc (f *genericValue) IsBoolFlag() bool {\n\tif f.val == nil {\n\t\treturn false\n\t}\n\tbf, ok := f.val.(boolFlag)\n\treturn ok && bf.IsBoolFlag()\n}\n\n// Generic looks up the value of a local GenericFlag, returns\n// nil if not found\nfunc (cmd *Command) Generic(name string) Value {\n\tif v, ok := cmd.Value(name).(Value); ok {\n\t\ttracef(\"generic available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"generic NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "flag_impl.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n// Value represents a value as used by cli.\n// For now it implements the golang flag.Value interface\ntype Value interface {\n\tflag.Value\n\tflag.Getter\n}\n\ntype boolFlag interface {\n\tIsBoolFlag() bool\n}\n\ntype multiValueParsingConfig struct {\n\t// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is \",\"\n\tSliceFlagSeparator string\n\t// DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false\n\tDisableSliceFlagSeparator bool\n\t// MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is \"=\"\n\tMapFlagKeyValueSeparator string\n}\n\ntype multiValueParsingConfigSetter interface {\n\t// configuration of parsing\n\tsetMultiValueParsingConfig(c multiValueParsingConfig)\n}\n\n// ValueCreator is responsible for creating a flag.Value emulation\n// as well as custom formatting\n//\n//\tT specifies the type\n//\tC specifies the config for the type\ntype ValueCreator[T any, C any] interface {\n\tCreate(T, *T, C) Value\n\tToString(T) string\n}\n\n// NoConfig is for flags which dont need a custom configuration\ntype NoConfig struct{}\n\n// FlagBase [T,C,VC] is a generic flag base which can be used\n// as a boilerplate to implement the most common interfaces\n// used by urfave/cli.\n//\n//\tT specifies the type\n//\tC specifies the configuration required(if any for that flag type)\n//\tVC specifies the value creator which creates the flag.Value emulation\ntype FlagBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName             string                                   `json:\"name\"`             // name of the flag\n\tCategory         string                                   `json:\"category\"`         // category of the flag, if any\n\tDefaultText      string                                   `json:\"defaultText\"`      // default text of the flag for usage purposes\n\tHideDefault      bool                                     `json:\"hideDefault\"`      // whether to hide the default value in output\n\tUsage            string                                   `json:\"usage\"`            // usage string for help output\n\tSources          ValueSourceChain                         `json:\"-\"`                // sources to load flag value from\n\tRequired         bool                                     `json:\"required\"`         // whether the flag is required or not\n\tHidden           bool                                     `json:\"hidden\"`           // whether to hide the flag in help output\n\tLocal            bool                                     `json:\"local\"`            // whether the flag needs to be applied to subcommands as well\n\tValue            T                                        `json:\"defaultValue\"`     // default value for this flag if not set by from any source\n\tDestination      *T                                       `json:\"-\"`                // destination pointer for value when set\n\tAliases          []string                                 `json:\"aliases\"`          // Aliases that are allowed for this flag\n\tTakesFile        bool                                     `json:\"takesFileArg\"`     // whether this flag takes a file argument, mainly for shell completion purposes\n\tAction           func(context.Context, *Command, T) error `json:\"-\"`                // Action callback to be called when flag is set\n\tConfig           C                                        `json:\"config\"`           // Additional/Custom configuration associated with this flag type\n\tOnlyOnce         bool                                     `json:\"onlyOnce\"`         // whether this flag can be duplicated on the command line\n\tValidator        func(T) error                            `json:\"-\"`                // custom function to validate this flag value\n\tValidateDefaults bool                                     `json:\"validateDefaults\"` // whether to validate defaults or not\n\n\t// unexported fields for internal use\n\tcount      int   // number of times the flag has been set\n\thasBeenSet bool  // whether the flag has been set from env or file\n\tapplied    bool  // whether the flag has been applied to a flag set already\n\tcreator    VC    // value creator for this flag type\n\tvalue      Value // value representing this flag's value\n}\n\n// GetValue returns the flags value as string representation and an empty\n// string if the flag takes no value at all.\nfunc (f *FlagBase[T, C, V]) GetValue() string {\n\tvar v V\n\treturn v.ToString(f.Value)\n}\n\n// TypeName returns the type of the flag.\nfunc (f *FlagBase[T, C, V]) TypeName() string {\n\tty := reflect.TypeOf(f.Value)\n\tif ty == nil {\n\t\treturn \"\"\n\t}\n\t// convert the typename to generic type\n\tconvertToGenericType := func(name string) string {\n\t\tprefixMap := map[string]string{\n\t\t\t\"float\": \"float\",\n\t\t\t\"int\":   \"int\",\n\t\t\t\"uint\":  \"uint\",\n\t\t}\n\t\tfor prefix, genericType := range prefixMap {\n\t\t\tif strings.HasPrefix(name, prefix) {\n\t\t\t\treturn genericType\n\t\t\t}\n\t\t}\n\t\treturn strings.ToLower(name)\n\t}\n\n\tswitch ty.Kind() {\n\t// if it is a Slice, then return the slice's inner type. Will nested slices be used in the future?\n\tcase reflect.Slice:\n\t\telemType := ty.Elem()\n\t\treturn convertToGenericType(elemType.Name())\n\t// if it is a Map, then return the map's key and value types.\n\tcase reflect.Map:\n\t\tkeyType := ty.Key()\n\t\tvalueType := ty.Elem()\n\t\treturn fmt.Sprintf(\"%s=%s\", convertToGenericType(keyType.Name()), convertToGenericType(valueType.Name()))\n\tdefault:\n\t\treturn convertToGenericType(ty.Name())\n\t}\n}\n\n// PostParse populates the flag given the flag set and environment\nfunc (f *FlagBase[T, C, V]) PostParse() error {\n\ttracef(\"postparse (flag=%[1]q)\", f.Name)\n\n\tif !f.hasBeenSet {\n\t\tif val, source, found := f.Sources.LookupWithSource(); found {\n\t\t\tif val != \"\" || reflect.TypeOf(f.Value).Kind() == reflect.String {\n\t\t\t\tif err := f.Set(f.Name, val); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s\",\n\t\t\t\t\t\tval, f.Value, source, f.Name, err,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if val == \"\" && reflect.TypeOf(f.Value).Kind() == reflect.Bool {\n\t\t\t\t_ = f.Set(f.Name, \"false\")\n\t\t\t}\n\n\t\t\tf.hasBeenSet = true\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// pass configuration of parsing to value\nfunc (f *FlagBase[T, C, V]) setMultiValueParsingConfig(c multiValueParsingConfig) {\n\ttracef(\"setMultiValueParsingConfig %T, %+v\", f.value, f.value)\n\tif cf, ok := f.value.(multiValueParsingConfigSetter); ok {\n\t\tcf.setMultiValueParsingConfig(c)\n\t}\n}\n\nfunc (f *FlagBase[T, C, V]) PreParse() error {\n\tnewVal := f.Value\n\n\tif f.Destination == nil {\n\t\tf.value = f.creator.Create(newVal, new(T), f.Config)\n\t} else {\n\t\tf.value = f.creator.Create(newVal, f.Destination, f.Config)\n\t}\n\n\t// Validate the given default or values set from external sources as well\n\tif f.Validator != nil && f.ValidateDefaults {\n\t\tif err := f.Validator(f.value.Get().(T)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tf.applied = true\n\treturn nil\n}\n\n// Set applies given value from string\nfunc (f *FlagBase[T, C, V]) Set(_ string, val string) error {\n\ttracef(\"apply (flag=%[1]q)\", f.Name)\n\n\t// TODO move this phase into a separate flag initialization function\n\t// if flag has been applied previously then it would have already been set\n\t// from env or file. So no need to apply the env set again. However\n\t// lots of units tests prior to persistent flags assumed that the\n\t// flag can be applied to different flag sets multiple times while still\n\t// keeping the env set.\n\tif !f.applied || f.Local {\n\t\tif err := f.PreParse(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tf.applied = true\n\t}\n\n\tif f.count == 1 && f.OnlyOnce {\n\t\treturn fmt.Errorf(\"cant duplicate this flag\")\n\t}\n\n\tf.count++\n\tif err := f.value.Set(val); err != nil {\n\t\treturn err\n\t}\n\tf.hasBeenSet = true\n\tif f.Validator != nil {\n\t\tif err := f.Validator(f.value.Get().(T)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (f *FlagBase[T, C, V]) Get() any {\n\tif f.value != nil {\n\t\treturn f.value.Get()\n\t}\n\treturn f.Value\n}\n\n// IsDefaultVisible returns true if the flag is not hidden, otherwise false\nfunc (f *FlagBase[T, C, V]) IsDefaultVisible() bool {\n\treturn !f.HideDefault\n}\n\n// String returns a readable representation of this value (for usage defaults)\nfunc (f *FlagBase[T, C, V]) String() string {\n\treturn FlagStringer(f)\n}\n\n// IsSet returns whether or not the flag has been set through env or file\nfunc (f *FlagBase[T, C, V]) IsSet() bool {\n\treturn f.hasBeenSet\n}\n\n// Names returns the names of the flag\nfunc (f *FlagBase[T, C, V]) Names() []string {\n\treturn FlagNames(f.Name, f.Aliases)\n}\n\n// IsRequired returns whether or not the flag is required\nfunc (f *FlagBase[T, C, V]) IsRequired() bool {\n\treturn f.Required\n}\n\n// IsVisible returns true if the flag is not hidden, otherwise false\nfunc (f *FlagBase[T, C, V]) IsVisible() bool {\n\treturn !f.Hidden\n}\n\n// GetCategory returns the category of the flag\nfunc (f *FlagBase[T, C, V]) GetCategory() string {\n\treturn f.Category\n}\n\nfunc (f *FlagBase[T, C, V]) SetCategory(c string) {\n\tf.Category = c\n}\n\n// GetUsage returns the usage string for the flag\nfunc (f *FlagBase[T, C, V]) GetUsage() string {\n\treturn f.Usage\n}\n\n// GetEnvVars returns the env vars for this flag\nfunc (f *FlagBase[T, C, V]) GetEnvVars() []string {\n\treturn f.Sources.EnvKeys()\n}\n\n// TakesValue returns true if the flag takes a value, otherwise false\nfunc (f *FlagBase[T, C, V]) TakesValue() bool {\n\tvar t T\n\treturn reflect.TypeOf(t) == nil || reflect.TypeOf(t).Kind() != reflect.Bool\n}\n\n// GetDefaultText returns the default text for this flag\nfunc (f *FlagBase[T, C, V]) GetDefaultText() string {\n\treturn f.DefaultText\n}\n\n// RunAction executes flag action if set\nfunc (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error {\n\tif f.Action != nil {\n\t\treturn f.Action(ctx, cmd, f.value.Get().(T))\n\t}\n\n\treturn nil\n}\n\n// IsMultiValueFlag returns true if the value type T can take multiple\n// values from cmd line. This is true for slice and map type flags\nfunc (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool {\n\t// TBD how to specify\n\tif reflect.TypeOf(f.Value) == nil {\n\t\treturn false\n\t}\n\tkind := reflect.TypeOf(f.Value).Kind()\n\treturn kind == reflect.Slice || kind == reflect.Map\n}\n\n// IsLocal returns false if flag needs to be persistent across subcommands\nfunc (f *FlagBase[T, C, VC]) IsLocal() bool {\n\treturn f.Local\n}\n\n// IsBoolFlag returns whether the flag doesnt need to accept args\nfunc (f *FlagBase[T, C, VC]) IsBoolFlag() bool {\n\tbf, ok := f.value.(boolFlag)\n\treturn ok && bf.IsBoolFlag()\n}\n\n// Count returns the number of times this flag has been invoked\nfunc (f *FlagBase[T, C, VC]) Count() int {\n\treturn f.count\n}\n"
  },
  {
    "path": "flag_int.go",
    "content": "package cli\n\nimport (\n\t\"strconv\"\n\t\"unsafe\"\n)\n\ntype (\n\tIntFlag   = FlagBase[int, IntegerConfig, intValue[int]]\n\tInt8Flag  = FlagBase[int8, IntegerConfig, intValue[int8]]\n\tInt16Flag = FlagBase[int16, IntegerConfig, intValue[int16]]\n\tInt32Flag = FlagBase[int32, IntegerConfig, intValue[int32]]\n\tInt64Flag = FlagBase[int64, IntegerConfig, intValue[int64]]\n)\n\n// IntegerConfig is the configuration for all integer type flags\ntype IntegerConfig struct {\n\tBase int\n}\n\n// -- int Value\ntype intValue[T int | int8 | int16 | int32 | int64] struct {\n\tval  *T\n\tbase int\n}\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (i intValue[T]) Create(val T, p *T, c IntegerConfig) Value {\n\t*p = val\n\n\treturn &intValue[T]{\n\t\tval:  p,\n\t\tbase: c.Base,\n\t}\n}\n\nfunc (i intValue[T]) ToString(b T) string {\n\ti.val = &b\n\treturn i.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (i *intValue[T]) Set(s string) error {\n\tv, err := strconv.ParseInt(s, i.base, int(unsafe.Sizeof(T(0))*8))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*i.val = T(v)\n\treturn err\n}\n\nfunc (i *intValue[T]) Get() any { return *i.val }\n\nfunc (i *intValue[T]) String() string {\n\tbase := i.base\n\tif base == 0 {\n\t\tbase = 10\n\t}\n\n\treturn strconv.FormatInt(int64(*i.val), base)\n}\n\n// Int looks up the value of a local Int64Flag, returns\n// 0 if not found\nfunc (cmd *Command) Int(name string) int {\n\treturn getInt[int](cmd, name)\n}\n\n// Int8 looks up the value of a local Int8Flag, returns\n// 0 if not found\nfunc (cmd *Command) Int8(name string) int8 {\n\treturn getInt[int8](cmd, name)\n}\n\n// Int16 looks up the value of a local Int16Flag, returns\n// 0 if not found\nfunc (cmd *Command) Int16(name string) int16 {\n\treturn getInt[int16](cmd, name)\n}\n\n// Int32 looks up the value of a local Int32Flag, returns\n// 0 if not found\nfunc (cmd *Command) Int32(name string) int32 {\n\treturn getInt[int32](cmd, name)\n}\n\n// Int64 looks up the value of a local Int64Flag, returns\n// 0 if not found\nfunc (cmd *Command) Int64(name string) int64 {\n\treturn getInt[int64](cmd, name)\n}\n\nfunc getInt[T int | int8 | int16 | int32 | int64](cmd *Command, name string) T {\n\tif v, ok := cmd.Value(name).(T); ok {\n\t\ttracef(\"int available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\n\t\treturn v\n\t}\n\n\ttracef(\"int NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn 0\n}\n"
  },
  {
    "path": "flag_int_slice.go",
    "content": "package cli\n\ntype (\n\tIntSlice       = SliceBase[int, IntegerConfig, intValue[int]]\n\tInt8Slice      = SliceBase[int8, IntegerConfig, intValue[int8]]\n\tInt16Slice     = SliceBase[int16, IntegerConfig, intValue[int16]]\n\tInt32Slice     = SliceBase[int32, IntegerConfig, intValue[int32]]\n\tInt64Slice     = SliceBase[int64, IntegerConfig, intValue[int64]]\n\tIntSliceFlag   = FlagBase[[]int, IntegerConfig, IntSlice]\n\tInt8SliceFlag  = FlagBase[[]int8, IntegerConfig, Int8Slice]\n\tInt16SliceFlag = FlagBase[[]int16, IntegerConfig, Int16Slice]\n\tInt32SliceFlag = FlagBase[[]int32, IntegerConfig, Int32Slice]\n\tInt64SliceFlag = FlagBase[[]int64, IntegerConfig, Int64Slice]\n)\n\nvar (\n\tNewIntSlice   = NewSliceBase[int, IntegerConfig, intValue[int]]\n\tNewInt8Slice  = NewSliceBase[int8, IntegerConfig, intValue[int8]]\n\tNewInt16Slice = NewSliceBase[int16, IntegerConfig, intValue[int16]]\n\tNewInt32Slice = NewSliceBase[int32, IntegerConfig, intValue[int32]]\n\tNewInt64Slice = NewSliceBase[int64, IntegerConfig, intValue[int64]]\n)\n\n// IntSlice looks up the value of a local IntSliceFlag, returns\n// nil if not found\nfunc (cmd *Command) IntSlice(name string) []int {\n\treturn getNumberSlice[int](cmd, name)\n}\n\n// Int8Slice looks up the value of a local Int8SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Int8Slice(name string) []int8 {\n\treturn getNumberSlice[int8](cmd, name)\n}\n\n// Int16Slice looks up the value of a local Int16SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Int16Slice(name string) []int16 {\n\treturn getNumberSlice[int16](cmd, name)\n}\n\n// Int32Slice looks up the value of a local Int32SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Int32Slice(name string) []int32 {\n\treturn getNumberSlice[int32](cmd, name)\n}\n\n// Int64Slice looks up the value of a local Int64SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Int64Slice(name string) []int64 {\n\treturn getNumberSlice[int64](cmd, name)\n}\n"
  },
  {
    "path": "flag_int_slice_test.go",
    "content": "package cli\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCommand_IntSlice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []int\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &IntSliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []int{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &IntSliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []int{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.IntSlice(name), \"IntSlice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Int8Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []int8\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Int8SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []int8{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Int8SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []int8{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Int8Slice(name), \"Int8Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Int16Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []int16\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Int16SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []int16{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Int16SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []int16{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Int16Slice(name), \"Int16Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Int32Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []int32\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Int32SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []int32{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Int32SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []int32{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Int32Slice(name), \"Int32Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Int64Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []int64\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Int64SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []int64{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Int64SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []int64{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Int64Slice(name), \"Int64Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "flag_int_test.go",
    "content": "package cli\n\nimport (\n\t\"flag\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestIntFlag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue int\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &IntFlag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"-234567\"},\n\t\t\texpectedValue: -234567,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &IntFlag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Int(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInt8Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue int8\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Int8Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"127\"},\n\t\t\texpectedValue: 127,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Int8Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Int8(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInt16Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue int16\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Int16Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"32767\"},\n\t\t\texpectedValue: 32767,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Int16Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"out of range\",\n\t\t\tflag: &Int16Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"32768\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Int16(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInt32Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue int32\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Int32Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"2147483647\"},\n\t\t\texpectedValue: 2147483647,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Int32Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"out of range\",\n\t\t\tflag: &Int32Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"2147483648\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Int32(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInt64Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue int64\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Int64Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"-2147483648\"},\n\t\t\texpectedValue: -2147483648,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Int64Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Int64(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestIntFlagExt(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          *flag.Flag\n\t\tconfig        IntegerConfig\n\t\targuments     []string\n\t\tflagName      string\n\t\texpectedValue string\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{},\n\t\t\targuments:     []string{\"--number\", \"234567\"},\n\t\t\tflagName:      \"number\",\n\t\t\texpectedValue: \"234567\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{Base: 10},\n\t\t\targuments:     []string{\"--number\", \"234567\"},\n\t\t\tflagName:      \"number\",\n\t\t\texpectedValue: \"234567\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid hex\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName:     \"number\",\n\t\t\t\tDefValue: \"FFFF\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{Base: 16},\n\t\t\targuments:     []string{\"--number\", \"39447\"},\n\t\t\tflagName:      \"number\",\n\t\t\texpectedValue: \"39447\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid hex default\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName:     \"number\",\n\t\t\t\tDefValue: \"FFFF\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{Base: 16},\n\t\t\texpectedValue: \"ffff\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar uValue intValue[int]\n\t\t\tvar u int\n\n\t\t\tf := &extFlag{f: tt.flag}\n\n\t\t\ttt.flag.Value = uValue.Create(u, &u, tt.config)\n\n\t\t\tif tt.config.Base != 0 && tt.config.Base != 10 {\n\t\t\t\tt.Skipf(\"skipping %q with base %d, only base 10 is supported\", tt.name, tt.config.Base)\n\t\t\t}\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{f},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expectedValue, f.GetValue())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "flag_map_impl.go",
    "content": "package cli\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// MapBase wraps map[string]T to satisfy flag.Value\ntype MapBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tdict             *map[string]T\n\thasBeenSet       bool\n\tvalue            Value\n\tmultiValueConfig multiValueParsingConfig\n}\n\nfunc (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value {\n\t*p = map[string]T{}\n\tfor k, v := range val {\n\t\t(*p)[k] = v\n\t}\n\tvar t T\n\tnp := new(T)\n\tvar vc VC\n\treturn &MapBase[T, C, VC]{\n\t\tdict:  p,\n\t\tvalue: vc.Create(t, np, c),\n\t}\n}\n\n// NewMapBase makes a *MapBase with default values\nfunc NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string]T) *MapBase[T, C, VC] {\n\treturn &MapBase[T, C, VC]{\n\t\tdict: &defaults,\n\t}\n}\n\n// configuration of slicing\nfunc (i *MapBase[T, C, VC]) setMultiValueParsingConfig(c multiValueParsingConfig) {\n\ti.multiValueConfig = c\n\tmvc := &i.multiValueConfig\n\ttracef(\n\t\t\"set map parsing config - keyValueSeparator '%s', slice separator '%s', disable separator:%v\",\n\t\tmvc.MapFlagKeyValueSeparator,\n\t\tmvc.SliceFlagSeparator,\n\t\tmvc.DisableSliceFlagSeparator,\n\t)\n}\n\n// Set parses the value and appends it to the list of values\nfunc (i *MapBase[T, C, VC]) Set(value string) error {\n\tif !i.hasBeenSet {\n\t\t*i.dict = map[string]T{}\n\t\ti.hasBeenSet = true\n\t}\n\n\tif strings.HasPrefix(value, slPfx) {\n\t\t// Deserializing assumes overwrite\n\t\t_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, \"\", 1)), &i.dict)\n\t\ti.hasBeenSet = true\n\t\treturn nil\n\t}\n\n\tmvc := &i.multiValueConfig\n\tkeyValueSeparator := mvc.MapFlagKeyValueSeparator\n\tif len(keyValueSeparator) == 0 {\n\t\tkeyValueSeparator = defaultMapFlagKeyValueSeparator\n\t}\n\n\ttracef(\n\t\t\"splitting map value '%s', keyValueSeparator '%s', slice separator '%s', disable separator:%v\",\n\t\tvalue,\n\t\tkeyValueSeparator,\n\t\tmvc.SliceFlagSeparator,\n\t\tmvc.DisableSliceFlagSeparator,\n\t)\n\tfor _, item := range flagSplitMultiValues(value, mvc.SliceFlagSeparator, mvc.DisableSliceFlagSeparator) {\n\t\tkey, value, ok := strings.Cut(item, keyValueSeparator)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"item %q is missing separator %q\", item, keyValueSeparator)\n\t\t}\n\t\tif err := i.value.Set(value); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t(*i.dict)[key] = i.value.Get().(T)\n\t}\n\n\treturn nil\n}\n\n// String returns a readable representation of this value (for usage defaults)\nfunc (i *MapBase[T, C, VC]) String() string {\n\tv := i.Value()\n\tvar t T\n\tif reflect.TypeOf(t).Kind() == reflect.String {\n\t\treturn fmt.Sprintf(\"%v\", v)\n\t}\n\treturn fmt.Sprintf(\"%T{%s}\", v, i.ToString(v))\n}\n\n// Serialize allows MapBase to fulfill Serializer\nfunc (i *MapBase[T, C, VC]) Serialize() string {\n\tjsonBytes, _ := json.Marshal(i.dict)\n\treturn fmt.Sprintf(\"%s%s\", slPfx, string(jsonBytes))\n}\n\n// Value returns the mapping of values set by this flag\nfunc (i *MapBase[T, C, VC]) Value() map[string]T {\n\tif i.dict == nil {\n\t\treturn map[string]T{}\n\t}\n\treturn *i.dict\n}\n\n// Get returns the mapping of values set by this flag\nfunc (i *MapBase[T, C, VC]) Get() interface{} {\n\treturn *i.dict\n}\n\nfunc (i MapBase[T, C, VC]) ToString(t map[string]T) string {\n\tvar defaultVals []string\n\tvar vc VC\n\tfor _, k := range sortedKeys(t) {\n\t\tdefaultVals = append(defaultVals, k+defaultMapFlagKeyValueSeparator+vc.ToString(t[k]))\n\t}\n\treturn strings.Join(defaultVals, \", \")\n}\n\nfunc sortedKeys[T any](dict map[string]T) []string {\n\tkeys := make([]string, 0, len(dict))\n\tfor k := range dict {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\treturn keys\n}\n"
  },
  {
    "path": "flag_mutex.go",
    "content": "package cli\n\n// MutuallyExclusiveFlags defines a mutually exclusive flag group\n// Multiple option paths can be provided out of which\n// only one can be defined on cmdline\n// So for example\n// [ --foo | [ --bar something --darth somethingelse ] ]\ntype MutuallyExclusiveFlags struct {\n\t// Flag list\n\tFlags [][]Flag\n\n\t// whether this group is required\n\tRequired bool\n\n\t// Category to apply to all flags within group\n\tCategory string\n}\n\nfunc (grp MutuallyExclusiveFlags) check(_ *Command) error {\n\toneSet := false\n\te := &mutuallyExclusiveGroup{}\n\n\tfor _, grpf := range grp.Flags {\n\t\tfor _, f := range grpf {\n\t\t\tif f.IsSet() {\n\t\t\t\tif oneSet {\n\t\t\t\t\te.flag2Name = f.Names()[0]\n\t\t\t\t\treturn e\n\t\t\t\t}\n\t\t\t\te.flag1Name = f.Names()[0]\n\t\t\t\toneSet = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif oneSet {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif !oneSet && grp.Required {\n\t\treturn &mutuallyExclusiveGroupRequiredFlag{flags: &grp}\n\t}\n\treturn nil\n}\n\nfunc (grp MutuallyExclusiveFlags) propagateCategory() {\n\tfor _, grpf := range grp.Flags {\n\t\tfor _, f := range grpf {\n\t\t\tif cf, ok := f.(CategorizableFlag); ok {\n\t\t\t\tcf.SetCategory(grp.Category)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "flag_mutex_test.go",
    "content": "package cli\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc newCommand() *Command {\n\treturn &Command{\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\t\tName: \"i\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName:    \"s\",\n\t\t\t\t\t\t\tSources: EnvVars(\"S_VAR\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&BoolWithInverseFlag{\n\t\t\t\t\t\t\tName: \"b\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t&Int64Flag{\n\t\t\t\t\t\t\tName:    \"t\",\n\t\t\t\t\t\t\tAliases: []string{\"ai\"},\n\t\t\t\t\t\t\tSources: EnvVars(\"T_VAR\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc TestFlagMutuallyExclusiveFlags(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\targs     []string\n\t\terrStr   string\n\t\trequired bool\n\t\tenvs     map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"simple\",\n\t\t},\n\t\t{\n\t\t\tname: \"set one flag\",\n\t\t\targs: []string{\"--i\", \"10\"},\n\t\t},\n\t\t{\n\t\t\tname:   \"set both flags\",\n\t\t\targs:   []string{\"--i\", \"11\", \"--ai\", \"12\"},\n\t\t\terrStr: \"option i cannot be set along with option ai\",\n\t\t},\n\t\t{\n\t\t\tname:     \"required none set\",\n\t\t\trequired: true,\n\t\t\terrStr:   \"one of these flags needs to be provided\",\n\t\t},\n\t\t{\n\t\t\tname:     \"required one set\",\n\t\t\targs:     []string{\"--i\", \"10\"},\n\t\t\trequired: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"required both set\",\n\t\t\targs:     []string{\"--i\", \"11\", \"--ai\", \"12\"},\n\t\t\terrStr:   \"option i cannot be set along with option ai\",\n\t\t\trequired: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"set env var\",\n\t\t\trequired: true,\n\t\t\tenvs: map[string]string{\n\t\t\t\t\"S_VAR\": \"some\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tif test.envs != nil {\n\t\t\t\tfor k, v := range test.envs {\n\t\t\t\t\tt.Setenv(k, v)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcmd := newCommand()\n\t\t\tcmd.MutuallyExclusiveFlags[0].Required = test.required\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"foo\"}, test.args...))\n\t\t\tif test.errStr == \"\" {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"Expected mutual exclusion error\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tswitch err.(type) {\n\t\t\tcase (*mutuallyExclusiveGroup), (*mutuallyExclusiveGroupRequiredFlag):\n\t\t\t\tif !strings.Contains(err.Error(), test.errStr) {\n\t\t\t\t\tt.Logf(\"Invalid error string %v\", err)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tt.Errorf(\"got invalid error type %T\", err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "flag_number_slice.go",
    "content": "package cli\n\ntype numberType interface {\n\tint | int8 | int16 | int32 | int64 | float32 | float64\n}\n\nfunc getNumberSlice[T numberType](cmd *Command, name string) []T {\n\tif v, ok := cmd.Value(name).([]T); ok {\n\t\ttracef(\"%T slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", *new(T), name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"%T slice NOT available for flag name %[1]q (cmd=%[2]q)\", *new(T), name, cmd.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "flag_number_slice_test.go",
    "content": "package cli\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_getNumberSlice_int64(t *testing.T) {\n\tf := &Int64SliceFlag{Name: \"numbers\"}\n\n\tcmd := &Command{\n\t\tName:      \"mock\",\n\t\tFlags:     []Flag{f},\n\t\tWriter:    io.Discard,\n\t\tErrWriter: io.Discard,\n\t}\n\n\terr := f.Set(\"\", \"1,2,3\")\n\trequire.NoError(t, err)\n\n\texpected := []int64{1, 2, 3}\n\n\tassert.Equal(t, expected, getNumberSlice[int64](cmd, \"numbers\"))\n}\n\nfunc Test_getNumberSlice_float64(t *testing.T) {\n\tf := &Float64SliceFlag{Name: \"numbers\"}\n\n\tcmd := &Command{\n\t\tName:      \"mock\",\n\t\tFlags:     []Flag{f},\n\t\tWriter:    io.Discard,\n\t\tErrWriter: io.Discard,\n\t}\n\n\terr := f.Set(\"\", \"1,2,3\")\n\trequire.NoError(t, err)\n\n\texpected := []float64{1, 2, 3}\n\n\tassert.Equal(t, expected, getNumberSlice[float64](cmd, \"numbers\"))\n}\n"
  },
  {
    "path": "flag_slice_base.go",
    "content": "package cli\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n// SliceBase wraps []T to satisfy flag.Value\ntype SliceBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tslice                 *[]T\n\thasBeenSet            bool\n\tvalue                 Value\n\tsliceSeparator        string\n\tdisableSliceSeparator bool\n}\n\nfunc (i SliceBase[T, C, VC]) Create(val []T, p *[]T, c C) Value {\n\t*p = []T{}\n\t*p = append(*p, val...)\n\tvar t T\n\tnp := new(T)\n\tvar vc VC\n\treturn &SliceBase[T, C, VC]{\n\t\tslice: p,\n\t\tvalue: vc.Create(t, np, c),\n\t}\n}\n\n// NewSliceBase makes a *SliceBase with default values\nfunc NewSliceBase[T any, C any, VC ValueCreator[T, C]](defaults ...T) *SliceBase[T, C, VC] {\n\treturn &SliceBase[T, C, VC]{\n\t\tslice: &defaults,\n\t}\n}\n\n// configuration of slicing\nfunc (i *SliceBase[T, C, VC]) setMultiValueParsingConfig(c multiValueParsingConfig) {\n\ti.disableSliceSeparator = c.DisableSliceFlagSeparator\n\ti.sliceSeparator = c.SliceFlagSeparator\n\ttracef(\"set slice parsing config - slice separator '%s', disable separator:%v\", i.sliceSeparator, i.disableSliceSeparator)\n}\n\n// Set parses the value and appends it to the list of values\nfunc (i *SliceBase[T, C, VC]) Set(value string) error {\n\tif !i.hasBeenSet {\n\t\t*i.slice = []T{}\n\t\ti.hasBeenSet = true\n\t}\n\n\tif strings.HasPrefix(value, slPfx) {\n\t\t// Deserializing assumes overwrite\n\t\t_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, \"\", 1)), &i.slice)\n\t\ti.hasBeenSet = true\n\t\treturn nil\n\t}\n\n\ttrimSpace := true\n\t// hack. How do we know if we should trim spaces?\n\t// it makes sense only for string slice flags which have\n\t// an option to not trim spaces. So by default we trim spaces\n\t// otherwise we let the underlying value type handle it.\n\tvar t T\n\tif reflect.TypeOf(t).Kind() == reflect.String {\n\t\ttrimSpace = false\n\t}\n\n\ttracef(\"splitting slice value '%s', separator '%s', disable separator:%v\", value, i.sliceSeparator, i.disableSliceSeparator)\n\tfor _, s := range flagSplitMultiValues(value, i.sliceSeparator, i.disableSliceSeparator) {\n\t\tif trimSpace {\n\t\t\ts = strings.TrimSpace(s)\n\t\t}\n\t\tif err := i.value.Set(s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*i.slice = append(*i.slice, i.value.Get().(T))\n\t}\n\n\treturn nil\n}\n\n// String returns a readable representation of this value (for usage defaults)\nfunc (i *SliceBase[T, C, VC]) String() string {\n\tvar defaultVals []string\n\tvar v VC\n\tfor _, s := range *i.slice {\n\t\tdefaultVals = append(defaultVals, v.ToString(s))\n\t}\n\treturn strings.Join(defaultVals, \", \")\n}\n\n// Serialize allows SliceBase to fulfill Serializer\nfunc (i *SliceBase[T, C, VC]) Serialize() string {\n\tjsonBytes, _ := json.Marshal(i.slice)\n\treturn fmt.Sprintf(\"%s%s\", slPfx, string(jsonBytes))\n}\n\n// Value returns the slice of values set by this flag\nfunc (i *SliceBase[T, C, VC]) Value() []T {\n\tif i.slice == nil {\n\t\treturn nil\n\t}\n\treturn *i.slice\n}\n\n// Get returns the slice of values set by this flag\nfunc (i *SliceBase[T, C, VC]) Get() interface{} {\n\treturn *i.slice\n}\n\nfunc (i SliceBase[T, C, VC]) ToString(t []T) string {\n\ti.slice = &t\n\treturn i.String()\n}\n"
  },
  {
    "path": "flag_string.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype StringFlag = FlagBase[string, StringConfig, stringValue]\n\n// StringConfig defines the configuration for string flags\ntype StringConfig struct {\n\t// Whether to trim whitespace of parsed value\n\tTrimSpace bool\n}\n\n// -- string Value\ntype stringValue struct {\n\tdestination *string\n\ttrimSpace   bool\n}\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (s stringValue) Create(val string, p *string, c StringConfig) Value {\n\t*p = val\n\treturn &stringValue{\n\t\tdestination: p,\n\t\ttrimSpace:   c.TrimSpace,\n\t}\n}\n\nfunc (s stringValue) ToString(val string) string {\n\ts.destination = &val\n\treturn s.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (s *stringValue) Set(val string) error {\n\tif s.trimSpace {\n\t\tval = strings.TrimSpace(val)\n\t}\n\t*s.destination = val\n\treturn nil\n}\n\nfunc (s *stringValue) Get() any { return *s.destination }\n\nfunc (s *stringValue) String() string {\n\tif s.destination != nil && *s.destination != \"\" {\n\t\treturn fmt.Sprintf(\"%q\", *s.destination)\n\t}\n\treturn \"\"\n}\n\nfunc (cmd *Command) String(name string) string {\n\tif v, ok := cmd.Value(name).(string); ok {\n\t\ttracef(\"string available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"string NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn \"\"\n}\n"
  },
  {
    "path": "flag_string_map.go",
    "content": "package cli\n\ntype (\n\tStringMap     = MapBase[string, StringConfig, stringValue]\n\tStringMapFlag = FlagBase[map[string]string, StringConfig, StringMap]\n)\n\nvar NewStringMap = NewMapBase[string, StringConfig, stringValue]\n\n// StringMap looks up the value of a local StringMapFlag, returns\n// nil if not found\nfunc (cmd *Command) StringMap(name string) map[string]string {\n\tif v, ok := cmd.Value(name).(map[string]string); ok {\n\t\ttracef(\"string map available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"string map NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "flag_string_slice.go",
    "content": "package cli\n\ntype (\n\tStringSlice     = SliceBase[string, StringConfig, stringValue]\n\tStringSliceFlag = FlagBase[[]string, StringConfig, StringSlice]\n)\n\nvar NewStringSlice = NewSliceBase[string, StringConfig, stringValue]\n\n// StringSlice looks up the value of a local StringSliceFlag, returns\n// nil if not found\nfunc (cmd *Command) StringSlice(name string) []string {\n\tif v, ok := cmd.Value(name).([]string); ok {\n\t\ttracef(\"string slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"string slice NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "flag_test.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype Parser [2]string\n\nfunc (p *Parser) Set(value string) error {\n\tparts := strings.Split(value, \",\")\n\tif len(parts) != 2 {\n\t\treturn fmt.Errorf(\"invalid format\")\n\t}\n\n\t(*p)[0] = parts[0]\n\t(*p)[1] = parts[1]\n\n\treturn nil\n}\n\nfunc (p *Parser) String() string {\n\treturn fmt.Sprintf(\"%s,%s\", p[0], p[1])\n}\n\nfunc (p *Parser) Get() interface{} {\n\treturn p\n}\n\nvar boolFlagTests = []struct {\n\tname     string\n\texpected string\n}{\n\t{\"help\", \"--help\\t\"},\n\t{\"h\", \"-h\\t\"},\n}\n\nfunc TestBoolFlagHelpOutput(t *testing.T) {\n\tfor _, test := range boolFlagTests {\n\t\tfl := &BoolFlag{Name: test.name}\n\t\toutput := fl.String()\n\t\tassert.Equal(t, test.expected, output)\n\t}\n}\n\nfunc TestBoolFlagApply_SetsAllNames(t *testing.T) {\n\tv := false\n\tcmd := buildMinimalTestCommand()\n\tcmd.Flags = []Flag{\n\t\t&BoolFlag{Name: \"wat\", Aliases: []string{\"W\", \"huh\"}, Destination: &v},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--wat\", \"-W\", \"--huh\"})\n\tassert.NoError(t, err)\n\tassert.True(t, v)\n}\n\nfunc TestBoolFlagValueFromCommand(t *testing.T) {\n\ttf := &BoolFlag{Name: \"trueflag\"}\n\tff := &BoolFlag{Name: \"falseflag\"}\n\n\tcmd := buildMinimalTestCommand()\n\tcmd.Flags = []Flag{\n\t\ttf,\n\t\tff,\n\t}\n\n\tr := require.New(t)\n\tr.NoError(cmd.Set(tf.Name, \"true\"))\n\tr.NoError(cmd.Set(ff.Name, \"false\"))\n\tr.True(cmd.Bool(tf.Name))\n\tr.False(cmd.Bool(ff.Name))\n}\n\nfunc TestBoolFlagApply_SetsCount(t *testing.T) {\n\tv := false\n\tcount := 0\n\tcmd := buildMinimalTestCommand()\n\tcmd.Flags = []Flag{\n\t\t&BoolFlag{Name: \"wat\", Aliases: []string{\"W\", \"huh\"}, Destination: &v, Config: BoolConfig{Count: &count}},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--wat\", \"-W\", \"--huh\"}))\n\tassert.True(t, v)\n\tassert.Equal(t, 3, count)\n}\n\nfunc TestBoolFlagCountFromCommand(t *testing.T) {\n\tboolCountTests := []struct {\n\t\tname          string\n\t\tinput         []string\n\t\texpectedVal   bool\n\t\texpectedCount int\n\t}{\n\t\t{\n\t\t\tname:          \"3 count\",\n\t\t\tinput:         []string{\"main\", \"-tf\", \"-w\", \"-huh\"},\n\t\t\texpectedVal:   true,\n\t\t\texpectedCount: 3,\n\t\t},\n\t\t{\n\t\t\tname:          \"single count\",\n\t\t\tinput:         []string{\"main\", \"-huh\"},\n\t\t\texpectedVal:   true,\n\t\t\texpectedCount: 1,\n\t\t},\n\t\t{\n\t\t\tname:          \"zero count\",\n\t\t\tinput:         []string{\"main\"},\n\t\t\texpectedVal:   false,\n\t\t\texpectedCount: 0,\n\t\t},\n\t}\n\n\tflags := func() []Flag {\n\t\treturn []Flag{\n\t\t\t&BoolFlag{Name: \"tf\", Aliases: []string{\"w\", \"huh\"}},\n\t\t\t&BoolWithInverseFlag{Name: \"tf\", Aliases: []string{\"w\", \"huh\"}},\n\t\t}\n\t}\n\tfor index := range flags() {\n\t\tfor _, bct := range boolCountTests {\n\t\t\tt.Run(bct.name, func(t *testing.T) {\n\t\t\t\tbf := flags()[index]\n\t\t\t\tcmd := &Command{\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\tbf,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tr := require.New(t)\n\n\t\t\t\tr.NoError(cmd.Run(buildTestContext(t), bct.input))\n\n\t\t\t\tfor _, alias := range bf.Names() {\n\t\t\t\t\tr.Equal(bct.expectedCount, cmd.Count(alias))\n\t\t\t\t\tr.Equal(bct.expectedVal, cmd.Value(alias))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestFlagsFromEnv(t *testing.T) {\n\ttestCases := []struct {\n\t\tname        string\n\t\tinput       string\n\t\toutput      any\n\t\tfl          Flag\n\t\terrContains string\n\t}{\n\t\t{\n\t\t\tname:   \"BoolFlag valid true\",\n\t\t\tinput:  \"1\",\n\t\t\toutput: true,\n\t\t\tfl:     &BoolFlag{Name: \"debug\", Sources: EnvVars(\"DEBUG\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"BoolFlag valid false\",\n\t\t\tinput:  \"false\",\n\t\t\toutput: false,\n\t\t\tfl:     &BoolFlag{Name: \"debug\", Sources: EnvVars(\"DEBUG\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"BoolFlag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: true,\n\t\t\tfl:     &BoolFlag{Name: \"debug\", Sources: EnvVars(\"DEBUG\")},\n\t\t\terrContains: `could not parse \"foobar\" as bool value from environment variable ` +\n\t\t\t\t`\"DEBUG\" for flag debug:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"BoolInverse Empty\",\n\t\t\toutput: false,\n\t\t\tfl:     &BoolWithInverseFlag{Name: \"debug\", Sources: EnvVars(\"DEBUG\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"DurationFlag valid\",\n\t\t\tinput:  \"1s\",\n\t\t\toutput: 1 * time.Second,\n\t\t\tfl:     &DurationFlag{Name: \"time\", Sources: EnvVars(\"TIME\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"DurationFlag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: false,\n\t\t\tfl:     &DurationFlag{Name: \"time\", Sources: EnvVars(\"TIME\")},\n\t\t\terrContains: `could not parse \"foobar\" as time.Duration value from environment ` +\n\t\t\t\t`variable \"TIME\" for flag time:`,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"Float64Flag valid\",\n\t\t\tinput:  \"1.2\",\n\t\t\toutput: 1.2,\n\t\t\tfl:     &FloatFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Float64Flag valid from int\",\n\t\t\tinput:  \"1\",\n\t\t\toutput: 1.0,\n\t\t\tfl:     &FloatFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Float64Flag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: 0,\n\t\t\tfl:     &FloatFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"foobar\" as float64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"Int64Flag valid\",\n\t\t\tinput:  \"1\",\n\t\t\toutput: int64(1),\n\t\t\tfl:     &Int64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64Flag invalid from float\",\n\t\t\tinput:  \"1.2\",\n\t\t\toutput: 0,\n\t\t\tfl:     &Int64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"1.2\" as int64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64Flag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: 0,\n\t\t\tfl:     &Int64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"foobar\" as int64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64Flag valid from hex\",\n\t\t\tinput:  \"deadBEEF\",\n\t\t\toutput: int64(3735928559),\n\t\t\tfl:     &Int64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\"), Config: IntegerConfig{Base: 16}},\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64Flag invalid from octal\",\n\t\t\tinput:  \"08\",\n\t\t\toutput: 0,\n\t\t\tfl:     &Int64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\"), Config: IntegerConfig{Base: 8}},\n\t\t\terrContains: `could not parse \"08\" as int64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"Float64SliceFlag valid\",\n\t\t\tinput:  \"1.0,2\",\n\t\t\toutput: []float64{1, 2},\n\t\t\tfl:     &FloatSliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Float64SliceFlag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: []float64{},\n\t\t\tfl:     &FloatSliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"foobar\" as []float64 value from environment ` +\n\t\t\t\t`variable \"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Generic\",\n\t\t\tinput:  \"foo,bar\",\n\t\t\toutput: &Parser{\"foo\", \"bar\"},\n\t\t\tfl:     &GenericFlag{Name: \"names\", Value: &Parser{}, Sources: EnvVars(\"NAMES\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64SliceFlag valid\",\n\t\t\tinput:  \"1,2\",\n\t\t\toutput: []int64{1, 2},\n\t\t\tfl:     &Int64SliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64SliceFlag invalid from float\",\n\t\t\tinput:  \"1.2,2\",\n\t\t\toutput: []int64{},\n\t\t\tfl:     &Int64SliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"1.2,2\" as []int64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Int64SliceFlag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: []int64{},\n\t\t\tfl:     &Int64SliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"foobar\" as []int64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"Uint64SliceFlag valid\",\n\t\t\tinput:  \"1,2\",\n\t\t\toutput: []uint64{1, 2},\n\t\t\tfl:     &Uint64SliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64SliceFlag invalid with float\",\n\t\t\tinput:  \"1.2,2\",\n\t\t\toutput: []uint64{},\n\t\t\tfl:     &Uint64SliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"1.2,2\" as []uint64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64SliceFlag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: []uint64{},\n\t\t\tfl:     &Uint64SliceFlag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"foobar\" as []uint64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"StringFlag valid\",\n\t\t\tinput:  \"foo\",\n\t\t\toutput: \"foo\",\n\t\t\tfl:     &StringFlag{Name: \"name\", Sources: EnvVars(\"NAME\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"StringFlag valid with TrimSpace\",\n\t\t\tinput:  \" foo\",\n\t\t\toutput: \"foo\",\n\t\t\tfl:     &StringFlag{Name: \"names\", Sources: EnvVars(\"NAMES\"), Config: StringConfig{TrimSpace: true}},\n\t\t},\n\n\t\t{\n\t\t\tname:   \"StringSliceFlag valid\",\n\t\t\tinput:  \"foo,bar\",\n\t\t\toutput: []string{\"foo\", \"bar\"},\n\t\t\tfl:     &StringSliceFlag{Name: \"names\", Sources: EnvVars(\"NAMES\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"StringSliceFlag valid with TrimSpace\",\n\t\t\tinput:  \"foo , bar \",\n\t\t\toutput: []string{\"foo\", \"bar\"},\n\t\t\tfl:     &StringSliceFlag{Name: \"names\", Sources: EnvVars(\"NAMES\"), Config: StringConfig{TrimSpace: true}},\n\t\t},\n\t\t{\n\t\t\tname:   \"StringSliceFlag valid without TrimSpace\",\n\t\t\tinput:  \"foo , bar \",\n\t\t\toutput: []string{\"foo \", \" bar \"},\n\t\t\tfl:     &StringSliceFlag{Name: \"names\", Sources: EnvVars(\"NAMES\")},\n\t\t},\n\n\t\t{\n\t\t\tname:   \"StringMapFlag valid\",\n\t\t\tinput:  \"foo=bar,empty=\",\n\t\t\toutput: map[string]string{\"foo\": \"bar\", \"empty\": \"\"},\n\t\t\tfl:     &StringMapFlag{Name: \"names\", Sources: EnvVars(\"NAMES\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"StringMapFlag valid with TrimSpace\",\n\t\t\tinput:  \"foo= bar \",\n\t\t\toutput: map[string]string{\"foo\": \"bar\"},\n\t\t\tfl:     &StringMapFlag{Name: \"names\", Sources: EnvVars(\"NAMES\"), Config: StringConfig{TrimSpace: true}},\n\t\t},\n\n\t\t{\n\t\t\tname:   \"Uint64Flag valid\",\n\t\t\tinput:  \"1\",\n\t\t\toutput: uint64(1),\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64Flag valid leading zero\",\n\t\t\tinput:  \"08\",\n\t\t\toutput: uint64(8),\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\"), Config: IntegerConfig{Base: 10}},\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64Flag valid from octal\",\n\t\t\tinput:  \"755\",\n\t\t\toutput: uint64(493),\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\"), Config: IntegerConfig{Base: 8}},\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64Flag valid from hex\",\n\t\t\tinput:  \"deadBEEF\",\n\t\t\toutput: uint64(3735928559),\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\"), Config: IntegerConfig{Base: 16}},\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64Flag invalid octal\",\n\t\t\tinput:  \"08\",\n\t\t\toutput: 0,\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\"), Config: IntegerConfig{Base: 8}},\n\t\t\terrContains: `could not parse \"08\" as uint64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64Flag invalid float\",\n\t\t\tinput:  \"1.2\",\n\t\t\toutput: 0,\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"1.2\" as uint64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t\t{\n\t\t\tname:   \"Uint64Flag invalid\",\n\t\t\tinput:  \"foobar\",\n\t\t\toutput: 0,\n\t\t\tfl:     &Uint64Flag{Name: \"seconds\", Sources: EnvVars(\"SECONDS\")},\n\t\t\terrContains: `could not parse \"foobar\" as uint64 value from environment variable ` +\n\t\t\t\t`\"SECONDS\" for flag seconds:`,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tr := require.New(t)\n\n\t\t\tr.Implements((*DocGenerationFlag)(nil), tc.fl)\n\t\t\tf := tc.fl.(DocGenerationFlag)\n\n\t\t\tenvVarSlice := f.GetEnvVars()\n\t\t\tt.Setenv(envVarSlice[0], tc.input)\n\n\t\t\tcmd := &Command{\n\t\t\t\tFlags: []Flag{tc.fl},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tr.Equal(tc.output, cmd.Value(tc.fl.Names()[0]))\n\t\t\t\t\tr.True(tc.fl.IsSet())\n\t\t\t\t\tr.Equal(tc.fl.Names(), cmd.FlagNames())\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), []string{\"run\"})\n\n\t\t\tif tc.errContains != \"\" {\n\t\t\t\tr.NotNil(err)\n\t\t\t\tr.ErrorContains(err, tc.errContains)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tr.NoError(err)\n\t\t})\n\t}\n}\n\ntype nodocFlag struct {\n\tFlag\n\n\tName string\n}\n\nfunc TestFlagStringifying(t *testing.T) {\n\tfor _, tc := range []struct {\n\t\tname     string\n\t\tfl       Flag\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"bool-flag\",\n\t\t\tfl:       &BoolFlag{Name: \"vividly\"},\n\t\t\texpected: \"--vividly\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"bool-flag-with-default-text\",\n\t\t\tfl:       &BoolFlag{Name: \"wildly\", DefaultText: \"scrambled\"},\n\t\t\texpected: \"--wildly\\t(default: scrambled)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"bool-inv-flag\",\n\t\t\tfl:       &BoolWithInverseFlag{Name: \"vividly\"},\n\t\t\texpected: \"--vividly, --no-vividly\\t(default: false)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"duration-flag\",\n\t\t\tfl:       &DurationFlag{Name: \"scream-for\"},\n\t\t\texpected: \"--scream-for duration\\t(default: 0s)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"duration-flag-with-default-text\",\n\t\t\tfl:       &DurationFlag{Name: \"feels-about\", DefaultText: \"whimsically\"},\n\t\t\texpected: \"--feels-about duration\\t(default: whimsically)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"float64-flag\",\n\t\t\tfl:       &FloatFlag{Name: \"arduous\"},\n\t\t\texpected: \"--arduous float\\t(default: 0)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"float64-flag-with-default-text\",\n\t\t\tfl:       &FloatFlag{Name: \"filibuster\", DefaultText: \"42\"},\n\t\t\texpected: \"--filibuster float\\t(default: 42)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"float64-slice-flag\",\n\t\t\tfl:       &FloatSliceFlag{Name: \"pizzas\"},\n\t\t\texpected: \"--pizzas float [ --pizzas float ]\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"float64-slice-flag-with-default-text\",\n\t\t\tfl:       &FloatSliceFlag{Name: \"pepperonis\", DefaultText: \"shaved\"},\n\t\t\texpected: \"--pepperonis float [ --pepperonis float ]\\t(default: shaved)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"generic-flag\",\n\t\t\tfl:       &GenericFlag{Name: \"yogurt\"},\n\t\t\texpected: \"--yogurt value\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"generic-flag-with-default-text\",\n\t\t\tfl:       &GenericFlag{Name: \"ricotta\", DefaultText: \"plops\"},\n\t\t\texpected: \"--ricotta value\\t(default: plops)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"int-flag\",\n\t\t\tfl:       &Int64Flag{Name: \"grubs\"},\n\t\t\texpected: \"--grubs int\\t(default: 0)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"int-flag-with-default-text\",\n\t\t\tfl:       &Int64Flag{Name: \"poisons\", DefaultText: \"11ty\"},\n\t\t\texpected: \"--poisons int\\t(default: 11ty)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"int-slice-flag\",\n\t\t\tfl:       &Int64SliceFlag{Name: \"pencils\"},\n\t\t\texpected: \"--pencils int [ --pencils int ]\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"int-slice-flag-with-default-text\",\n\t\t\tfl:       &Int64Flag{Name: \"pens\", DefaultText: \"-19\"},\n\t\t\texpected: \"--pens int\\t(default: -19)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint-slice-flag\",\n\t\t\tfl:       &Uint64SliceFlag{Name: \"pencils\"},\n\t\t\texpected: \"--pencils uint [ --pencils uint ]\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint-slice-flag-with-default-text\",\n\t\t\tfl:       &Uint64Flag{Name: \"pens\", DefaultText: \"29\"},\n\t\t\texpected: \"--pens uint\\t(default: 29)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"int64-flag\",\n\t\t\tfl:       &Int64Flag{Name: \"flume\"},\n\t\t\texpected: \"--flume int\\t(default: 0)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"int64-flag-with-default-text\",\n\t\t\tfl:       &Int64Flag{Name: \"shattering\", DefaultText: \"22\"},\n\t\t\texpected: \"--shattering int\\t(default: 22)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint64-slice-flag\",\n\t\t\tfl:       &Uint64SliceFlag{Name: \"drawers\"},\n\t\t\texpected: \"--drawers uint [ --drawers uint ]\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint64-slice-flag-with-default-text\",\n\t\t\tfl:       &Uint64SliceFlag{Name: \"handles\", DefaultText: \"-2\"},\n\t\t\texpected: \"--handles uint [ --handles uint ]\\t(default: -2)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"string-flag\",\n\t\t\tfl:       &StringFlag{Name: \"arf-sound\"},\n\t\t\texpected: \"--arf-sound string\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"string-flag-with-default-text\",\n\t\t\tfl:       &StringFlag{Name: \"woof-sound\", DefaultText: \"urp\"},\n\t\t\texpected: \"--woof-sound string\\t(default: urp)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"string-slice-flag\",\n\t\t\tfl:       &StringSliceFlag{Name: \"meow-sounds\"},\n\t\t\texpected: \"--meow-sounds string [ --meow-sounds string ]\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"string-slice-flag-with-default-text\",\n\t\t\tfl:       &StringSliceFlag{Name: \"moo-sounds\", DefaultText: \"awoo\"},\n\t\t\texpected: \"--moo-sounds string [ --moo-sounds string ]\\t(default: awoo)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"timestamp-flag\",\n\t\t\tfl:       &TimestampFlag{Name: \"eating\"},\n\t\t\texpected: \"--eating time\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"timestamp-flag-with-default-text\",\n\t\t\tfl:       &TimestampFlag{Name: \"sleeping\", DefaultText: \"earlier\"},\n\t\t\texpected: \"--sleeping time\\t(default: earlier)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint-flag\",\n\t\t\tfl:       &Uint64Flag{Name: \"jars\"},\n\t\t\texpected: \"--jars uint\\t(default: 0)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint-flag-with-default-text\",\n\t\t\tfl:       &Uint64Flag{Name: \"bottles\", DefaultText: \"99\"},\n\t\t\texpected: \"--bottles uint\\t(default: 99)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint64-flag\",\n\t\t\tfl:       &Uint64Flag{Name: \"cans\"},\n\t\t\texpected: \"--cans uint\\t(default: 0)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"uint64-flag-with-default-text\",\n\t\t\tfl:       &Uint64Flag{Name: \"tubes\", DefaultText: \"13\"},\n\t\t\texpected: \"--tubes uint\\t(default: 13)\",\n\t\t},\n\t\t{\n\t\t\tname:     \"nodoc-flag\",\n\t\t\tfl:       &nodocFlag{Name: \"scarecrow\"},\n\t\t\texpected: \"\",\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(ct *testing.T) {\n\t\t\ts := stringifyFlag(tc.fl)\n\t\t\tassert.Equal(t, tc.expected, s, \"stringified flag %q does not match expected\", s)\n\t\t})\n\t}\n}\n\nvar stringFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tusage    string\n\tvalue    string\n\texpected string\n}{\n\t{\"foo\", nil, \"\", \"\", \"--foo string\\t\"},\n\t{\"f\", nil, \"\", \"\", \"-f string\\t\"},\n\t{\"f\", nil, \"The total `foo` desired\", \"all\", \"-f foo\\tThe total foo desired (default: \\\"all\\\")\"},\n\t{\"test\", nil, \"\", \"Something\", \"--test string\\t(default: \\\"Something\\\")\"},\n\t{\"config\", []string{\"c\"}, \"Load configuration from `FILE`\", \"\", \"--config FILE, -c FILE\\tLoad configuration from FILE\"},\n\t{\"config\", []string{\"c\"}, \"Load configuration from `CONFIG`\", \"config.json\", \"--config CONFIG, -c CONFIG\\tLoad configuration from CONFIG (default: \\\"config.json\\\")\"},\n}\n\nfunc TestStringFlagHelpOutput(t *testing.T) {\n\tfor _, test := range stringFlagTests {\n\t\tfl := &StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestStringFlagDefaultText(t *testing.T) {\n\tfl := &StringFlag{Name: \"foo\", Aliases: nil, Usage: \"amount of `foo` requested\", Value: \"none\", DefaultText: \"all of it\"}\n\texpected := \"--foo foo\\tamount of foo requested (default: all of it)\"\n\tassert.Equal(t, expected, fl.String())\n}\n\nfunc TestStringFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_FOO\", \"derp\")\n\n\tfor _, test := range stringFlagTests {\n\t\tfl := &StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, Sources: EnvVars(\"APP_FOO\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_FOO\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nvar _ = []struct {\n\tname     string\n\taliases  []string\n\tusage    string\n\tvalue    string\n\tprefixer FlagNamePrefixFunc\n\texpected string\n}{\n\t{name: \"foo\", usage: \"\", value: \"\", prefixer: func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"name: %s, ph: %s\", a, b)\n\t}, expected: \"name: foo, ph: value\\t\"},\n\t{name: \"f\", usage: \"\", value: \"\", prefixer: func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"name: %s, ph: %s\", a, b)\n\t}, expected: \"name: f, ph: value\\t\"},\n\t{name: \"f\", usage: \"The total `foo` desired\", value: \"all\", prefixer: func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"name: %s, ph: %s\", a, b)\n\t}, expected: \"name: f, ph: foo\\tThe total foo desired (default: \\\"all\\\")\"},\n\t{name: \"test\", usage: \"\", value: \"Something\", prefixer: func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"name: %s, ph: %s\", a, b)\n\t}, expected: \"name: test, ph: value\\t(default: \\\"Something\\\")\"},\n\t{name: \"config\", aliases: []string{\"c\"}, usage: \"Load configuration from `FILE`\", value: \"\", prefixer: func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"name: %s, ph: %s\", a, b)\n\t}, expected: \"name: config,c, ph: FILE\\tLoad configuration from FILE\"},\n\t{name: \"config\", aliases: []string{\"c\"}, usage: \"Load configuration from `CONFIG`\", value: \"config.json\", prefixer: func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"name: %s, ph: %s\", a, b)\n\t}, expected: \"name: config,c, ph: CONFIG\\tLoad configuration from CONFIG (default: \\\"config.json\\\")\"},\n}\n\nfunc TestStringFlagApply_SetsAllNames(t *testing.T) {\n\tv := \"mmm\"\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"hay\", Aliases: []string{\"H\", \"hayyy\"}, Destination: &v},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--hay\", \"u\", \"-H\", \"yuu\", \"--hayyy\", \"YUUUU\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"YUUUU\", v)\n}\n\nfunc TestStringFlagValueFromCommand(t *testing.T) {\n\tf := &StringFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tf,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"foobar\"))\n\trequire.Equal(t, \"foobar\", cmd.String(f.Name))\n}\n\nvar _ = []struct {\n\tname     string\n\tenv      string\n\thinter   FlagEnvHintFunc\n\texpected string\n}{\n\t{\"foo\", \"\", func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"env: %s, str: %s\", a, b)\n\t}, \"env: , str: --foo value\\t\"},\n\t{\"f\", \"\", func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"env: %s, str: %s\", a, b)\n\t}, \"env: , str: -f value\\t\"},\n\t{\"foo\", \"ENV_VAR\", func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"env: %s, str: %s\", a, b)\n\t}, \"env: ENV_VAR, str: --foo value\\t\"},\n\t{\"f\", \"ENV_VAR\", func(a []string, b string) string {\n\t\treturn fmt.Sprintf(\"env: %s, str: %s\", a, b)\n\t}, \"env: ENV_VAR, str: -f value\\t\"},\n}\n\n// func TestFlagEnvHinter(t *testing.T) {\n//\tdefer func() {\n//\t\tFlagEnvHinter = withEnvHint\n//\t}()\n//\n//\tfor _, test := range envHintFlagTests {\n//\t\tFlagEnvHinter = test.hinter\n//\t\tfl := StringFlag{Name: test.name, Sources: ValueSources{test.env}}\n//\t\toutput := fl.String()\n//\t\tif output != test.expected {\n//\t\t\tt.Errorf(\"%q does not match %q\", output, test.expected)\n//\t\t}\n//\t}\n// }\n\nvar stringSliceFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tvalue    []string\n\texpected string\n}{\n\t{\"foo\", nil, []string{}, \"--foo string [ --foo string ]\\t\"},\n\t{\"f\", nil, []string{}, \"-f string [ -f string ]\\t\"},\n\t{\"f\", nil, []string{\"Lipstick\"}, \"-f string [ -f string ]\\t(default: \\\"Lipstick\\\")\"},\n\t{\"test\", nil, []string{\"Something\"}, \"--test string [ --test string ]\\t(default: \\\"Something\\\")\"},\n\t{\"dee\", []string{\"d\"}, []string{\"Inka\", \"Dinka\", \"dooo\"}, \"--dee string, -d string [ --dee string, -d string ]\\t(default: \\\"Inka\\\", \\\"Dinka\\\", \\\"dooo\\\")\"},\n}\n\nfunc TestStringSliceFlagHelpOutput(t *testing.T) {\n\tfor _, test := range stringSliceFlagTests {\n\t\tf := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}\n\t\tassert.Equal(t, test.expected, f.String())\n\t}\n}\n\nfunc TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_QWWX\", \"11,4\")\n\n\tfor _, test := range stringSliceFlagTests {\n\t\tfl := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, Sources: EnvVars(\"APP_QWWX\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_QWWX\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%q does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestStringSliceFlagApply_SetsAllNames(t *testing.T) {\n\tfl := &StringSliceFlag{Name: \"goat\", Aliases: []string{\"G\", \"gooots\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--goat\", \"aaa\", \"-G\", \"bbb\", \"--gooots\", \"eeeee\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestStringSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"vincent van goat,scape goat\")\n\tfl := &StringSliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\")}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"vincent van goat\", \"scape goat\"}, cmd.Value(\"goat\"))\n}\n\nfunc TestStringSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"vincent van goat,scape goat\")\n\tval := []string{`some default`, `values here`}\n\tfl := &StringSliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"vincent van goat\", \"scape goat\"}, cmd.Value(\"goat\"))\n}\n\nfunc TestStringSliceFlagApply_DefaultValueWithDestination(t *testing.T) {\n\tdefValue := []string{\"UA\", \"US\"}\n\tdest := []string{\"CA\"}\n\n\tfl := StringSliceFlag{Name: \"country\", Value: defValue, Destination: &dest}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, defValue, dest)\n}\n\nfunc TestStringSliceFlagValueFromCommand(t *testing.T) {\n\tf := &StringSliceFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tf,\n\t\t},\n\t}\n\n\trequire.NoError(t, cmd.Set(\"myflag\", \"a\"))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"b\"))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"c\"))\n\trequire.Equal(t, []string{\"a\", \"b\", \"c\"}, cmd.StringSlice(f.Name))\n}\n\nvar intFlagTests = []struct {\n\tname     string\n\texpected string\n}{\n\t{\"hats\", \"--hats int\\t(default: 9)\"},\n\t{\"H\", \"-H int\\t(default: 9)\"},\n}\n\nfunc TestIntFlagHelpOutput(t *testing.T) {\n\tfor _, test := range intFlagTests {\n\t\tfl := &Int64Flag{Name: test.name, Value: 9}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestIntFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_BAR\", \"2\")\n\n\tfor _, test := range intFlagTests {\n\t\tfl := &Int64Flag{Name: test.name, Sources: EnvVars(\"APP_BAR\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_BAR\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestIntFlagApply_SetsAllNames(t *testing.T) {\n\tv := int64(3)\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"banana\", Aliases: []string{\"B\", \"banannanana\"}, Destination: &v},\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\", \"--banana\", \"1\", \"-B\", \"2\", \"--banannanana\", \"5\"}))\n\tr.Equal(int64(5), v)\n}\n\nfunc TestIntFlagValueFromCommand(t *testing.T) {\n\tfl := &Int64Flag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"42\"))\n\trequire.Equal(t, int64(42), cmd.Int64(fl.Name))\n}\n\nvar uintFlagTests = []struct {\n\tname     string\n\texpected string\n}{\n\t{\"nerfs\", \"--nerfs uint\\t(default: 41)\"},\n\t{\"N\", \"-N uint\\t(default: 41)\"},\n}\n\nfunc TestUintFlagHelpOutput(t *testing.T) {\n\tfor _, test := range uintFlagTests {\n\t\tfl := &Uint64Flag{Name: test.name, Value: 41}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestUintFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_BAR\", \"2\")\n\n\tfor _, test := range uintFlagTests {\n\t\tfl := &Uint64Flag{Name: test.name, Sources: EnvVars(\"APP_BAR\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_BAR\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestUintFlagValueFromCommand(t *testing.T) {\n\tfl := &Uint64Flag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"42\"))\n\trequire.Equal(t, uint64(42), cmd.Uint64(fl.Name))\n}\n\nvar uint64FlagTests = []struct {\n\tname     string\n\texpected string\n}{\n\t{\"gerfs\", \"--gerfs uint\\t(default: 8589934582)\"},\n\t{\"G\", \"-G uint\\t(default: 8589934582)\"},\n}\n\nfunc TestUint64FlagHelpOutput(t *testing.T) {\n\tfor _, test := range uint64FlagTests {\n\t\tfl := Uint64Flag{Name: test.name, Value: 8589934582}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_BAR\", \"2\")\n\n\tfor _, test := range uint64FlagTests {\n\t\tfl := &Uint64Flag{Name: test.name, Sources: EnvVars(\"APP_BAR\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_BAR\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestUint64FlagValueFromCommand(t *testing.T) {\n\tf := &Uint64Flag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tf,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"42\"))\n\trequire.Equal(t, uint64(42), cmd.Uint64(f.Name))\n}\n\nvar durationFlagTests = []struct {\n\tname     string\n\texpected string\n}{\n\t{\"hooting\", \"--hooting duration\\t(default: 1s)\"},\n\t{\"H\", \"-H duration\\t(default: 1s)\"},\n}\n\nfunc TestDurationFlagHelpOutput(t *testing.T) {\n\tfor _, test := range durationFlagTests {\n\t\tfl := &DurationFlag{Name: test.name, Value: 1 * time.Second}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_BAR\", \"2h3m6s\")\n\n\tfor _, test := range durationFlagTests {\n\t\tfl := &DurationFlag{Name: test.name, Sources: EnvVars(\"APP_BAR\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_BAR\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestDurationFlagApply_SetsAllNames(t *testing.T) {\n\tv := time.Second * 20\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&DurationFlag{Name: \"howmuch\", Aliases: []string{\"H\", \"whyyy\"}, Destination: &v},\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--howmuch\", \"30s\", \"-H\", \"5m\", \"--whyyy\", \"30h\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, time.Hour*30, v)\n}\n\nfunc TestDurationFlagValueFromCommand(t *testing.T) {\n\tf := &DurationFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tf,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"42s\"))\n\trequire.Equal(t, 42*time.Second, cmd.Duration(f.Name))\n}\n\nvar intSliceFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tvalue    []int64\n\texpected string\n}{\n\t{\"heads\", nil, []int64{}, \"--heads int [ --heads int ]\\t\"},\n\t{\"H\", nil, []int64{}, \"-H int [ -H int ]\\t\"},\n\t{\"H\", []string{\"heads\"}, []int64{9, 3}, \"-H int, --heads int [ -H int, --heads int ]\\t(default: 9, 3)\"},\n}\n\nfunc TestIntSliceFlagHelpOutput(t *testing.T) {\n\tfor _, test := range intSliceFlagTests {\n\t\tfl := &Int64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_SMURF\", \"42,3\")\n\n\tfor _, test := range intSliceFlagTests {\n\t\tfl := &Int64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, Sources: EnvVars(\"APP_SMURF\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_SMURF\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%q does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestIntSliceFlagApply_SetsAllNames(t *testing.T) {\n\tfl := &Int64SliceFlag{Name: \"bits\", Aliases: []string{\"B\", \"bips\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--bits\", \"23\", \"-B\", \"3\", \"--bips\", \"99\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestIntSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1 , 2\")\n\n\tfl := &Int64SliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\")}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\"}))\n\tr.NoError(fl.PostParse())\n\tr.Equal([]int64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestIntSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1 , 2\")\n\tval := []int64{3, 4}\n\tfl := &Int64SliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\"}))\n\tr.Equal([]int64{3, 4}, val)\n\tr.Equal([]int64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestIntSliceFlagApply_DefaultValueWithDestination(t *testing.T) {\n\tdefValue := []int64{1, 2}\n\tdest := []int64{3}\n\n\tfl := &Int64SliceFlag{Name: \"country\", Value: defValue, Destination: &dest}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, defValue, dest)\n}\n\nfunc TestIntSliceFlagApply_ParentContext(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []int64{1, 2, 3}},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"child\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\trequire.Equalf(t, []int64{1, 2, 3}, cmd.Int64Slice(\"numbers\"), \"child context unable to view parent flag\")\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"child\"})\n}\n\nfunc TestIntSliceFlag_SetFromParentCommand(t *testing.T) {\n\tfl := &Int64SliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []int64{1, 2, 3, 4}}\n\n\tcmd := &Command{\n\t\tparent: &Command{\n\t\t\tFlags: []Flag{\n\t\t\t\tfl,\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.Equalf(t, []int64{1, 2, 3, 4}, cmd.Int64Slice(\"numbers\"), \"child context unable to view parent flag\")\n}\n\nfunc TestIntSliceFlagValueFromCommand(t *testing.T) {\n\tf := &Int64SliceFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tf,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"1\"))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"2\"))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"3\"))\n\trequire.Equal(t, []int64{1, 2, 3}, cmd.Int64Slice(f.Name))\n}\n\nvar uintSliceFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tvalue    []uint64\n\texpected string\n}{\n\t{\"heads\", nil, []uint64{}, \"--heads uint [ --heads uint ]\\t\"},\n\t{\"H\", nil, []uint64{}, \"-H uint [ -H uint ]\\t\"},\n\t{\n\t\t\"heads\",\n\t\t[]string{\"H\"},\n\t\t[]uint64{2, 17179869184},\n\t\t\"--heads uint, -H uint [ --heads uint, -H uint ]\\t(default: 2, 17179869184)\",\n\t},\n}\n\nfunc TestUintSliceFlagHelpOutput(t *testing.T) {\n\tfor _, test := range uintSliceFlagTests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tfl := &Uint64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}\n\t\t\trequire.Equal(t, test.expected, fl.String())\n\t\t})\n\t}\n}\n\nfunc TestUintSliceFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_SMURF\", \"42,17179869184\")\n\n\tfor _, test := range uintSliceFlagTests {\n\t\tfl := &Uint64SliceFlag{Name: test.name, Value: test.value, Sources: EnvVars(\"APP_SMURF\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_SMURF\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%q does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestUintSliceFlagApply_SetsAllNames(t *testing.T) {\n\tfl := &Uint64SliceFlag{Name: \"bits\", Aliases: []string{\"B\", \"bips\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--bits\", \"23\", \"-B\", \"3\", \"--bips\", \"99\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestUintSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1 , 2\")\n\n\tfl := &Uint64SliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\")}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\"}))\n\tr.Equal([]uint64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestUintSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1 , 2\")\n\tval := NewUint64Slice(3, 4)\n\tfl := &Uint64SliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val.Value()}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"\"}))\n\tr.Equal([]uint64{3, 4}, val.Value())\n\tr.Equal([]uint64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestUintSliceFlagApply_DefaultValueWithDestination(t *testing.T) {\n\tdefValue := []uint64{1, 2}\n\tvar dest []uint64\n\n\tfl := &Uint64SliceFlag{Name: \"country\", Value: defValue, Destination: &dest}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, defValue, dest)\n}\n\nfunc TestUint64SliceFlagApply_ParentContext(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Uint64SliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []uint64{1, 2, 3}},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"child\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\trequire.Equalf(\n\t\t\t\t\t\tt, []uint64{1, 2, 3}, cmd.Uint64Slice(\"numbers\"),\n\t\t\t\t\t\t\"child context unable to view parent flag\",\n\t\t\t\t\t)\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"child\"})\n}\n\nfunc TestUintSliceFlag_SetFromParentCommand(t *testing.T) {\n\tfl := &UintSliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []uint{1, 2, 3, 4}}\n\tcmd := &Command{\n\t\tparent: &Command{\n\t\t\tFlags: []Flag{\n\t\t\t\tfl,\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\tr.Equalf(\n\t\t[]uint{1, 2, 3, 4},\n\t\tcmd.UintSlice(\"numbers\"),\n\t\t\"child context unable to view parent flag\",\n\t)\n}\n\nfunc TestUintSliceFlag_ReturnNil(t *testing.T) {\n\tfl := &Uint64SliceFlag{}\n\n\tr := require.New(t)\n\tcmd := &Command{\n\t\tparent: &Command{\n\t\t\tFlags: []Flag{\n\t\t\t\tfl,\n\t\t\t},\n\t\t},\n\t}\n\tr.Equalf(\n\t\t[]uint64(nil),\n\t\tcmd.Uint64Slice(\"numbers\"),\n\t\t\"child context unable to view parent flag\",\n\t)\n}\n\nvar uint64SliceFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tvalue    []uint64\n\texpected string\n}{\n\t{\"heads\", nil, []uint64{}, \"--heads uint [ --heads uint ]\\t\"},\n\t{\"H\", nil, []uint64{}, \"-H uint [ -H uint ]\\t\"},\n\t{\n\t\t\"heads\",\n\t\t[]string{\"H\"},\n\t\t[]uint64{2, 17179869184},\n\t\t\"--heads uint, -H uint [ --heads uint, -H uint ]\\t(default: 2, 17179869184)\",\n\t},\n}\n\nfunc TestUint64SliceFlagHelpOutput(t *testing.T) {\n\tfor _, test := range uint64SliceFlagTests {\n\t\tfl := Uint64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestUint64SliceFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_SMURF\", \"42,17179869184\")\n\n\tfor _, test := range uint64SliceFlagTests {\n\t\tfl := Uint64SliceFlag{Name: test.name, Value: test.value, Sources: EnvVars(\"APP_SMURF\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_SMURF\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%q does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestUint64SliceFlagApply_SetsAllNames(t *testing.T) {\n\tfl := Uint64SliceFlag{Name: \"bits\", Aliases: []string{\"B\", \"bips\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--bits\", \"23\", \"-B\", \"3\", \"--bips\", \"99\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestUint64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1 , 2\")\n\tfl := Uint64SliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\")}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, []uint64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestUint64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1 , 2\")\n\tval := []uint64{3, 4}\n\tfl := Uint64SliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, []uint64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestUint64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {\n\tdefValue := []uint64{1, 2}\n\tdest := []uint64{3}\n\n\tfl := Uint64SliceFlag{Name: \"country\", Value: defValue, Destination: &dest}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\"})\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, defValue, dest)\n}\n\nfunc TestUint64SliceFlagApply_ParentCommand(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Uint64SliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []uint64{1, 2, 3}},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"child\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\trequire.Equalf(\n\t\t\t\t\t\tt, []uint64{1, 2, 3}, cmd.Uint64Slice(\"numbers\"),\n\t\t\t\t\t\t\"child context unable to view parent flag\",\n\t\t\t\t\t)\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"child\"})\n}\n\nfunc TestUint64SliceFlag_SetFromParentCommand(t *testing.T) {\n\tfl := &Uint64SliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []uint64{1, 2, 3, 4}}\n\tcmd := &Command{\n\t\tparent: &Command{\n\t\t\tFlags: []Flag{\n\t\t\t\tfl,\n\t\t\t},\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.Equalf(\n\t\t[]uint64{1, 2, 3, 4}, cmd.Uint64Slice(\"numbers\"),\n\t\t\"child context unable to view parent flag\",\n\t)\n}\n\nfunc TestUint64SliceFlag_ReturnNil(t *testing.T) {\n\tfl := &Uint64SliceFlag{}\n\tcmd := &Command{\n\t\tparent: &Command{\n\t\t\tFlags: []Flag{\n\t\t\t\tfl,\n\t\t\t},\n\t\t},\n\t}\n\tr := require.New(t)\n\tr.Equalf(\n\t\t[]uint64(nil), cmd.Uint64Slice(\"numbers\"),\n\t\t\"child context unable to view parent flag\",\n\t)\n}\n\nvar float64FlagTests = []struct {\n\tname     string\n\texpected string\n}{\n\t{\"hooting\", \"--hooting float\\t(default: 0.1)\"},\n\t{\"H\", \"-H float\\t(default: 0.1)\"},\n}\n\nfunc TestFloat64FlagHelpOutput(t *testing.T) {\n\tfor _, test := range float64FlagTests {\n\t\tf := &FloatFlag{Name: test.name, Value: 0.1}\n\t\tassert.Equal(t, test.expected, f.String())\n\t}\n}\n\nfunc TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_BAZ\", \"99.4\")\n\n\tfor _, test := range float64FlagTests {\n\t\tfl := &FloatFlag{Name: test.name, Sources: EnvVars(\"APP_BAZ\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_BAZ\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestFloat64FlagApply_SetsAllNames(t *testing.T) {\n\tv := 99.1\n\tfl := FloatFlag{Name: \"noodles\", Aliases: []string{\"N\", \"nurbles\"}, Destination: &v}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--noodles\", \"1.3\", \"-N\", \"11\", \"--nurbles\", \"43.33333\"}))\n\tassert.Equal(t, float64(43.33333), v)\n}\n\nfunc TestFloat64FlagValueFromCommand(t *testing.T) {\n\tfl := &FloatFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tfl,\n\t\t},\n\t}\n\trequire.NoError(t, cmd.Set(\"myflag\", \"1.23\"))\n\trequire.Equal(t, 1.23, cmd.Float(fl.Name))\n}\n\nvar float64SliceFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tvalue    []float64\n\texpected string\n}{\n\t{\"heads\", nil, []float64{}, \"--heads float [ --heads float ]\\t\"},\n\t{\"H\", nil, []float64{}, \"-H float [ -H float ]\\t\"},\n\t{\n\t\t\"heads\",\n\t\t[]string{\"H\"},\n\t\t[]float64{0.1234, -10.5},\n\t\t\"--heads float, -H float [ --heads float, -H float ]\\t(default: 0.1234, -10.5)\",\n\t},\n}\n\nfunc TestFloat64SliceFlagHelpOutput(t *testing.T) {\n\tfor _, test := range float64SliceFlagTests {\n\t\tfl := FloatSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_SMURF\", \"0.1234,-10.5\")\n\tfor _, test := range float64SliceFlagTests {\n\t\tfl := FloatSliceFlag{Name: test.name, Value: test.value, Sources: EnvVars(\"APP_SMURF\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_SMURF\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%q does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestFloat64SliceFlagApply_SetsAllNames(t *testing.T) {\n\tfl := FloatSliceFlag{Name: \"bits\", Aliases: []string{\"B\", \"bips\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--bits\", \"23\", \"-B\", \"3\", \"--bips\", \"99\"}))\n}\n\nfunc TestFloat64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1.0 , 2.0\")\n\tfl := FloatSliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\")}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, []float64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestFloat64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"1.0 , 2.0\")\n\tval := []float64{3.0, 4.0}\n\tfl := FloatSliceFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, []float64{1, 2}, cmd.Value(\"goat\"))\n}\n\nfunc TestFloat64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {\n\tdefValue := []float64{1.0, 2.0}\n\tdest := []float64{3}\n\n\tfl := FloatSliceFlag{Name: \"country\", Value: defValue, Destination: &dest}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, defValue, dest)\n}\n\nfunc TestFloat64SliceFlagValueFromCommand(t *testing.T) {\n\tfl := FloatSliceFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"1.23\"))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"4.56\"))\n\trequire.Equal(t, []float64{1.23, 4.56}, cmd.FloatSlice(fl.Name))\n}\n\nfunc TestFloat64SliceFlagApply_ParentCommand(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatSliceFlag{Name: \"numbers\", Aliases: []string{\"n\"}, Value: []float64{1.0, 2.0, 3.0}},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"child\",\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\trequire.Equalf(t, []float64{1.0, 2.0, 3.0}, cmd.FloatSlice(\"numbers\"), \"child context unable to view parent flag\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"child\"})\n}\n\nvar genericFlagTests = []struct {\n\tname     string\n\tvalue    Value\n\texpected string\n}{\n\t{\"toads\", &Parser{\"abc\", \"def\"}, \"--toads value\\ttest flag (default: abc,def)\"},\n\t{\"t\", &Parser{\"abc\", \"def\"}, \"-t value\\ttest flag (default: abc,def)\"},\n}\n\nfunc TestGenericFlagHelpOutput(t *testing.T) {\n\tfor _, test := range genericFlagTests {\n\t\tfl := &GenericFlag{Name: test.name, Value: test.value, Usage: \"test flag\"}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_ZAP\", \"3\")\n\n\tfor _, test := range genericFlagTests {\n\t\tfl := &GenericFlag{Name: test.name, Sources: EnvVars(\"APP_ZAP\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_ZAP\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%s does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestGenericFlagApply_SetsAllNames(t *testing.T) {\n\tfl := GenericFlag{Name: \"orbs\", Aliases: []string{\"O\", \"obrs\"}, Value: &Parser{}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--orbs\", \"eleventy,3\", \"-O\", \"4,bloop\", \"--obrs\", \"19,s\"}))\n}\n\nfunc TestGenericFlagValueFromCommand(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"foo\",\n\t\tFlags: []Flag{\n\t\t\t&GenericFlag{Name: \"myflag\", Value: &Parser{}},\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"foo\", \"--myflag\", \"abc,def\"}))\n\tassert.Equal(t, &Parser{\"abc\", \"def\"}, cmd.Generic(\"myflag\"))\n\tassert.Nil(t, cmd.Generic(\"someother\"))\n}\n\nfunc TestParseGenericFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_SERVE\", \"20,30\")\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&GenericFlag{\n\t\t\t\tName:    \"serve\",\n\t\t\t\tAliases: []string{\"s\"},\n\t\t\t\tValue:   &Parser{},\n\t\t\t\tSources: EnvVars(\"APP_SERVE\"),\n\t\t\t},\n\t\t},\n\t\tAction: func(ctx context.Context, cmd *Command) error {\n\t\t\tif !reflect.DeepEqual(cmd.Generic(\"serve\"), &Parser{\"20\", \"30\"}) {\n\t\t\t\tt.Errorf(\"main name not set from env\")\n\t\t\t}\n\t\t\tif !reflect.DeepEqual(cmd.Generic(\"s\"), &Parser{\"20\", \"30\"}) {\n\t\t\t\tt.Errorf(\"short name not set from env\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"run\"}))\n}\n\nfunc TestFlagActionFromEnv(t *testing.T) {\n\tt.Setenv(\"X\", \"42\")\n\tx := 0\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&IntFlag{\n\t\t\t\tName:    \"x\",\n\t\t\t\tSources: EnvVars(\"X\"),\n\t\t\t\tAction: func(ctx context.Context, cmd *Command, v int) error {\n\t\t\t\t\tx = v\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"run\"}))\n\tassert.Equal(t, cmd.Int(\"x\"), 42)\n\tassert.Equal(t, x, 42)\n}\n\nfunc TestParseShortOptionBoolError(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcmd.Flags = []Flag{\n\t\t&BoolFlag{Name: \"debug\", Aliases: []string{\"d\"}},\n\t\t&BoolFlag{Name: \"verbose\", Aliases: []string{\"v\"}},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"run\", \"-vd=notabool\"})\n\tassert.Error(t, err, \"expected error parsing invalid bool\")\n}\n\nfunc TestParseShortOptionIntError(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.Flags = []Flag{\n\t\t&IntFlag{Name: \"port\", Aliases: []string{\"p\"}},\n\t\t&BoolFlag{Name: \"debug\", Aliases: []string{\"d\"}},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"run\", \"-dp=notanint\"})\n\tassert.Error(t, err, \"expected error parsing invalid int\")\n}\n\nfunc TestParseMultiString(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, \"10\", cmd.String(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, \"10\", cmd.String(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\"})\n}\n\nfunc TestParseDestinationString(t *testing.T) {\n\tvar dest string\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName:        \"dest\",\n\t\t\t\tDestination: &dest,\n\t\t\t},\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\tassert.Equal(t, \"10\", dest, \"expected destination String 10\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"--dest\", \"10\"})\n}\n\nfunc TestParseMultiStringFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_COUNT\", \"20\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"count\", Aliases: []string{\"c\"}, Sources: EnvVars(\"APP_COUNT\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, \"20\", cmd.String(\"count\"), \"main name not set\")\n\t\t\tassert.Equal(t, \"20\", cmd.String(\"c\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringFromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_COUNT\", \"20\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{Name: \"count\", Aliases: []string{\"c\"}, Sources: EnvVars(\"COMPAT_COUNT\", \"APP_COUNT\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, \"20\", cmd.String(\"count\"), \"main name not set\")\n\t\t\tassert.Equal(t, \"20\", cmd.String(\"c\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringSlice(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Value: []string{}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"10\", \"20\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiStringSliceWithDefaults(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Value: []string{\"9\", \"2\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"10\", \"20\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiStringSliceWithDestination(t *testing.T) {\n\tdest := []string{}\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Destination: &dest},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"10\", \"20\"}\n\t\t\tassert.Equal(t, expected, dest, \"destination val not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiStringSliceWithDestinationAndEnv(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\tdest := []string{}\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Destination: &dest, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"10\", \"20\"}\n\t\t\tassert.Equal(t, expected, dest, \"destination val not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiFloat64SliceWithDestinationAndEnv(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\tdest := []float64{}\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatSliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Destination: &dest, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []float64{10, 20}\n\t\t\tassert.Equal(t, expected, dest, \"destination val not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiIntSliceWithDestinationAndEnv(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\tdest := []int64{}\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Destination: &dest, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\trequire.Equalf(t, []int64{10, 20}, dest, \"main name not set\")\n\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Value: []string{\"9\", \"2\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"9\", \"2\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringSliceFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []string{}, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"20\", \"30\", \"40\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"intervals\"), \"main name not set from env\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"i\"), \"short name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringSliceFromEnvWithDefaults(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []string{\"1\", \"2\", \"5\"}, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"20\", \"30\", \"40\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"intervals\"), \"main name not set from env\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"i\"), \"short name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringSliceFromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []string{}, Sources: EnvVars(\"COMPAT_INTERVALS\", \"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"20\", \"30\", \"40\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"intervals\"), \"main name not set from env\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"i\"), \"short name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []string{\"1\", \"2\", \"5\"}, Sources: EnvVars(\"COMPAT_INTERVALS\", \"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []string{\"20\", \"30\", \"40\"}\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"intervals\"), \"main name not set from env\")\n\t\t\tassert.Equal(t, expected, cmd.StringSlice(\"i\"), \"short name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiStringSliceFromEnvWithDestination(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\tdest := []string{}\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Destination: &dest, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\tassert.Equal(t, []string{\"20\", \"30\", \"40\"}, dest, \"destination value not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiInt(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, int64(10), cmd.Int64(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, int64(10), cmd.Int64(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\"})\n}\n\nfunc TestParseDestinationInt(t *testing.T) {\n\tvar dest int64\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:        \"dest\",\n\t\t\t\tDestination: &dest,\n\t\t\t},\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\tassert.Equal(t, int64(10), dest, \"expected destination Int64 10\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"--dest\", \"10\"})\n}\n\nfunc TestParseMultiIntFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_TIMEOUT_SECONDS\", \"10\")\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"timeout\", Aliases: []string{\"t\"}, Sources: EnvVars(\"APP_TIMEOUT_SECONDS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, int64(10), cmd.Int64(\"timeout\"), \"main name not set\")\n\t\t\tassert.Equal(t, int64(10), cmd.Int64(\"t\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiIntFromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_TIMEOUT_SECONDS\", \"10\")\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"timeout\", Aliases: []string{\"t\"}, Sources: EnvVars(\"COMPAT_TIMEOUT_SECONDS\", \"APP_TIMEOUT_SECONDS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, int64(10), cmd.Int64(\"timeout\"), \"main name not set\")\n\t\t\tassert.Equal(t, int64(10), cmd.Int64(\"t\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiIntSlice(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Value: []int64{}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tr := require.New(t)\n\n\t\t\tr.Equalf([]int64{10, 20}, cmd.Int64Slice(\"serve\"), \"main name not set\")\n\t\t\tr.Equalf([]int64{10, 20}, cmd.Int64Slice(\"s\"), \"short name not set\")\n\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiIntSliceWithDefaults(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Value: []int64{9, 2}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tr := require.New(t)\n\n\t\t\tr.Equalf([]int64{10, 20}, cmd.Int64Slice(\"serve\"), \"main name not set\")\n\t\t\tr.Equalf([]int64{10, 20}, cmd.Int64Slice(\"s\"), \"short name not set\")\n\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10\", \"-s\", \"20\"})\n}\n\nfunc TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"serve\", Aliases: []string{\"s\"}, Value: []int64{9, 2}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\texpected := []int64{9, 2}\n\t\t\tassert.Equal(t, expected, cmd.Int64Slice(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, expected, cmd.Int64Slice(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiIntSliceFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []int64{}, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tr := require.New(t)\n\n\t\t\tr.Equalf([]int64{20, 30, 40}, cmd.Int64Slice(\"intervals\"), \"main name not set from env\")\n\t\t\tr.Equalf([]int64{20, 30, 40}, cmd.Int64Slice(\"i\"), \"short name not set from env\")\n\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiIntSliceFromEnvWithDefaults(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []int64{1, 2, 5}, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tr := require.New(t)\n\n\t\t\tr.Equalf([]int64{20, 30, 40}, cmd.Int64Slice(\"intervals\"), \"main name not set from env\")\n\t\t\tr.Equalf([]int64{20, 30, 40}, cmd.Int64Slice(\"i\"), \"short name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiIntSliceFromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"20,30,40\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64SliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []int64{}, Sources: EnvVars(\"COMPAT_INTERVALS\", \"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tr := require.New(t)\n\n\t\t\tr.Equalf([]int64{20, 30, 40}, cmd.Int64Slice(\"intervals\"), \"main name not set from env\")\n\t\t\tr.Equalf([]int64{20, 30, 40}, cmd.Int64Slice(\"i\"), \"short name not set from env\")\n\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiFloat64(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, 10.2, cmd.Float(\"serve\"), \"main name not set\")\n\t\t\tassert.Equal(t, 10.2, cmd.Float(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"-s\", \"10.2\"})\n}\n\nfunc TestParseDestinationFloat64(t *testing.T) {\n\tvar dest float64\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{\n\t\t\t\tName:        \"dest\",\n\t\t\t\tDestination: &dest,\n\t\t\t},\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\tassert.Equal(t, 10.2, dest, \"expected destination Float64 10.2\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"--dest\", \"10.2\"})\n}\n\nfunc TestParseMultiFloat64FromEnv(t *testing.T) {\n\tt.Setenv(\"APP_TIMEOUT_SECONDS\", \"15.5\")\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{Name: \"timeout\", Aliases: []string{\"t\"}, Sources: EnvVars(\"APP_TIMEOUT_SECONDS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, 15.5, cmd.Float(\"timeout\"), \"main name not set\")\n\t\t\tassert.Equal(t, 15.5, cmd.Float(\"t\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiFloat64FromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_TIMEOUT_SECONDS\", \"15.5\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatFlag{Name: \"timeout\", Aliases: []string{\"t\"}, Sources: EnvVars(\"COMPAT_TIMEOUT_SECONDS\", \"APP_TIMEOUT_SECONDS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.Equal(t, 15.5, cmd.Float(\"timeout\"), \"main name not set\")\n\t\t\tassert.Equal(t, 15.5, cmd.Float(\"t\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiFloat64SliceFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"0.1,-10.5\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []float64{}, Sources: EnvVars(\"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\trequire.Equalf(t, []float64{0.1, -10.5}, cmd.FloatSlice(\"intervals\"), \"main name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiFloat64SliceFromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_INTERVALS\", \"0.1234,-10.5\")\n\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&FloatSliceFlag{Name: \"intervals\", Aliases: []string{\"i\"}, Value: []float64{}, Sources: EnvVars(\"COMPAT_INTERVALS\", \"APP_INTERVALS\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\trequire.Equalf(t, []float64{0.1234, -10.5}, cmd.FloatSlice(\"intervals\"), \"main name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiBool(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.True(t, cmd.Bool(\"serve\"), \"main name not set\")\n\t\t\tassert.True(t, cmd.Bool(\"s\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"--serve\"})\n}\n\nfunc TestParseBoolShortOptionHandle(t *testing.T) {\n\t_ = (&Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:                   \"foobar\",\n\t\t\t\tUseShortOptionHandling: true,\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tassert.True(t, cmd.Bool(\"serve\"), \"main name not set\")\n\t\t\t\t\tassert.True(t, cmd.Bool(\"option\"), \"short name not set\")\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"serve\", Aliases: []string{\"s\"}},\n\t\t\t\t\t&BoolFlag{Name: \"option\", Aliases: []string{\"o\"}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"foobar\", \"-so\"})\n}\n\nfunc TestParseDestinationBool(t *testing.T) {\n\tvar dest bool\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName:        \"dest\",\n\t\t\t\tDestination: &dest,\n\t\t\t},\n\t\t},\n\t\tAction: func(context.Context, *Command) error {\n\t\t\tassert.True(t, dest, \"expected destination Bool true\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"--dest\"})\n}\n\nfunc TestParseMultiBoolFromEnv(t *testing.T) {\n\tt.Setenv(\"APP_DEBUG\", \"1\")\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"debug\", Aliases: []string{\"d\"}, Sources: EnvVars(\"APP_DEBUG\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.True(t, cmd.Bool(\"debug\"), \"main name not set\")\n\t\t\tassert.True(t, cmd.Bool(\"d\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseMultiBoolFromEnvCascade(t *testing.T) {\n\tt.Setenv(\"APP_DEBUG\", \"1\")\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"debug\", Aliases: []string{\"d\"}, Sources: EnvVars(\"COMPAT_DEBUG\", \"APP_DEBUG\")},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.True(t, cmd.Bool(\"debug\"), \"main name not set from env\")\n\t\t\tassert.True(t, cmd.Bool(\"d\"), \"short name not set from env\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\"})\n}\n\nfunc TestParseBoolFromEnv(t *testing.T) {\n\tboolFlagTests := []struct {\n\t\tinput  string\n\t\toutput bool\n\t}{\n\t\t{\"\", false},\n\t\t{\"1\", true},\n\t\t{\"false\", false},\n\t\t{\"true\", true},\n\t}\n\n\tfor _, test := range boolFlagTests {\n\t\tt.Run(fmt.Sprintf(\"%[1]q %[2]v\", test.input, test.output), func(t *testing.T) {\n\t\t\tt.Setenv(\"DEBUG\", test.input)\n\t\t\t_ = (&Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"debug\", Aliases: []string{\"d\"}, Sources: EnvVars(\"DEBUG\")},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\t\t\tassert.Equal(t, test.output, cmd.Bool(\"debug\"))\n\t\t\t\t\tassert.Equal(t, test.output, cmd.Bool(\"d\"))\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}).Run(buildTestContext(t), []string{\"run\"})\n\t\t})\n\t}\n}\n\nfunc TestParseMultiBoolT(t *testing.T) {\n\t_ = (&Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"implode\", Aliases: []string{\"i\"}, Value: true},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.False(t, cmd.Bool(\"implode\"), \"main name not set\")\n\t\t\tassert.False(t, cmd.Bool(\"i\"), \"short name not set\")\n\t\t\treturn nil\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"run\", \"--implode=false\"})\n}\n\nfunc TestStringSlice_Serialized_Set(t *testing.T) {\n\tsl0 := NewStringSlice(\"a\", \"b\")\n\tser0 := sl0.Serialize()\n\n\trequire.GreaterOrEqual(t, len(ser0), len(slPfx), \"serialized shorter than expected\")\n\n\tsl1 := NewStringSlice(\"c\", \"d\")\n\t_ = sl1.Set(ser0)\n\n\trequire.Equal(t, sl0.String(), sl1.String(), \"pre and post serialization do not match\")\n}\n\nfunc TestIntSlice_Serialized_Set(t *testing.T) {\n\tsl0 := NewInt64Slice(1, 2)\n\tser0 := sl0.Serialize()\n\n\trequire.GreaterOrEqual(t, len(ser0), len(slPfx), \"serialized shorter than expected\")\n\n\tsl1 := NewInt64Slice(3, 4)\n\t_ = sl1.Set(ser0)\n\n\trequire.Equal(t, sl0.String(), sl1.String(), \"pre and post serialization do not match\")\n}\n\nfunc TestUintSlice_Serialized_Set(t *testing.T) {\n\tsl0 := NewUint64Slice(1, 2)\n\tser0 := sl0.Serialize()\n\n\trequire.GreaterOrEqual(t, len(ser0), len(slPfx), \"serialized shorter than expected\")\n\n\tsl1 := NewUint64Slice(3, 4)\n\t_ = sl1.Set(ser0)\n\n\trequire.Equal(t, sl0.String(), sl1.String(), \"pre and post serialization do not match\")\n}\n\nfunc TestUint64Slice_Serialized_Set(t *testing.T) {\n\tsl0 := NewUint64Slice(1, 2)\n\tser0 := sl0.Serialize()\n\n\trequire.GreaterOrEqual(t, len(ser0), len(slPfx), \"serialized shorter than expected\")\n\n\tsl1 := NewUint64Slice(3, 4)\n\t_ = sl1.Set(ser0)\n\n\trequire.Equal(t, sl0.String(), sl1.String(), \"pre and post serialization do not match\")\n}\n\nfunc TestStringMap_Serialized_Set(t *testing.T) {\n\tm0 := NewStringMap(map[string]string{\"a\": \"b\"})\n\tser0 := m0.Serialize()\n\n\trequire.GreaterOrEqual(t, len(ser0), len(slPfx), \"serialized shorter than expected\")\n\n\tm1 := NewStringMap(map[string]string{\"c\": \"d\"})\n\t_ = m1.Set(ser0)\n\n\trequire.Equal(t, m0.String(), m1.String(), \"pre and post serialization do not match\")\n}\n\nvar timestampFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tusage    string\n\texpected string\n}{\n\t{\"foo\", nil, \"\", \"--foo time\\t(default: 2020-04-10 01:01:01.000000001 +0000 UTC)\"},\n\t{\"f\", nil, \"all\", \"-f time\\tall (default: 2020-04-10 01:01:01.000000001 +0000 UTC)\"},\n}\n\nfunc TestTimestampFlagHelpOutput(t *testing.T) {\n\ttl, err := time.LoadLocation(\"UTC\")\n\tassert.NoError(t, err)\n\tfor _, test := range timestampFlagTests {\n\t\tvalue := time.Date(2020, time.April, 10, 1, 1, 1, 1, tl)\n\t\tfl := &TimestampFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: value}\n\t\tassert.Equal(t, test.expected, fl.String())\n\t}\n}\n\nfunc TestTimestamp_set(t *testing.T) {\n\tts := timestampValue{\n\t\ttimestamp:  nil,\n\t\thasBeenSet: false,\n\t\tlayouts:    []string{\"Jan 2, 2006 at 3:04pm (MST)\"},\n\t}\n\n\ttime1 := \"Feb 3, 2013 at 7:54pm (PST)\"\n\trequire.NoError(t, ts.Set(time1), \"Failed to parse time %s with layouts %v\", time1, ts.layouts)\n\trequire.True(t, ts.hasBeenSet, \"hasBeenSet is not true after setting a time\")\n\n\tts.hasBeenSet = false\n\tts.layouts = []string{time.RFC3339}\n\ttime2 := \"2006-01-02T15:04:05Z\"\n\trequire.NoError(t, ts.Set(time2), \"Failed to parse time %s with layout %v\", time2, ts.layouts)\n\trequire.True(t, ts.hasBeenSet, \"hasBeenSet is not true after setting a time\")\n}\n\nfunc TestTimestampFlagApply_SingleFormat(t *testing.T) {\n\texpectedResult, _ := time.Parse(time.RFC3339, \"2006-01-02T15:04:05Z\")\n\tfl := TimestampFlag{Name: \"time\", Aliases: []string{\"t\"}, Config: TimestampConfig{Layouts: []string{time.RFC3339}}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--time\", \"2006-01-02T15:04:05Z\"}))\n\tassert.Equal(t, expectedResult, cmd.Value(\"time\"))\n}\n\nfunc TestTimestampFlagApply_MultipleFormats(t *testing.T) {\n\tnow := time.Now().UTC()\n\n\ttestCases := []struct {\n\t\tcaseName          string\n\t\tlayoutsPrecisions map[string]time.Duration\n\t\texpRes            time.Time\n\t\texpErrValidation  func(err error) (validation error)\n\t}{\n\t\t{\n\t\t\tcaseName: \"all_valid_layouts\",\n\t\t\tlayoutsPrecisions: map[string]time.Duration{\n\t\t\t\ttime.RFC3339:  time.Second,\n\t\t\t\ttime.DateTime: time.Second,\n\t\t\t\ttime.RFC1123:  time.Second,\n\t\t\t},\n\t\t\texpRes: now.Truncate(time.Second),\n\t\t},\n\t\t{\n\t\t\tcaseName: \"one_invalid_layout\",\n\t\t\tlayoutsPrecisions: map[string]time.Duration{\n\t\t\t\ttime.RFC3339:  time.Second,\n\t\t\t\ttime.DateTime: time.Second,\n\t\t\t\t\"foo\":         0,\n\t\t\t},\n\t\t\texpRes: now.Truncate(time.Second),\n\t\t},\n\t\t{\n\t\t\tcaseName: \"multiple_invalid_layouts\",\n\t\t\tlayoutsPrecisions: map[string]time.Duration{\n\t\t\t\ttime.RFC3339:  time.Second,\n\t\t\t\t\"foo\":         0,\n\t\t\t\ttime.DateTime: time.Second,\n\t\t\t\t\"bar\":         0,\n\t\t\t},\n\t\t\texpRes: now.Truncate(time.Second),\n\t\t},\n\t\t{\n\t\t\tcaseName: \"all_invalid_layouts\",\n\t\t\tlayoutsPrecisions: map[string]time.Duration{\n\t\t\t\t\"foo\":                      0,\n\t\t\t\t\"2024-08-07 74:01:82Z-100\": 0,\n\t\t\t\t\"25:70\":                    0,\n\t\t\t\t\"\":                         0,\n\t\t\t},\n\t\t\texpErrValidation: func(err error) error {\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn errors.New(\"got nil err\")\n\t\t\t\t}\n\n\t\t\t\tfound := regexp.MustCompile(`(cannot parse \".+\" as \".*\")|(extra text: \".+\")`).Match([]byte(err.Error()))\n\t\t\t\tif !found {\n\t\t\t\t\treturn fmt.Errorf(\"given error does not satisfy pattern: %w\", err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcaseName: \"empty_layout\",\n\t\t\tlayoutsPrecisions: map[string]time.Duration{\n\t\t\t\t\"\": 0,\n\t\t\t},\n\t\t\texpErrValidation: func(err error) error {\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn errors.New(\"got nil err\")\n\t\t\t\t}\n\n\t\t\t\tfound := regexp.MustCompile(`extra text: \".+\"`).Match([]byte(err.Error()))\n\t\t\t\tif !found {\n\t\t\t\t\treturn fmt.Errorf(\"given error does not satisfy pattern: %w\", err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcaseName: \"nil_layouts_slice\",\n\t\t\texpErrValidation: func(err error) error {\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn errors.New(\"got nil err\")\n\t\t\t\t}\n\n\t\t\t\tfound := regexp.MustCompile(`got nil/empty layouts slice`).Match([]byte(err.Error()))\n\t\t\t\tif !found {\n\t\t\t\t\treturn fmt.Errorf(\"given error does not satisfy pattern: %w\", err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcaseName:          \"empty_layouts_slice\",\n\t\t\tlayoutsPrecisions: map[string]time.Duration{},\n\t\t\texpErrValidation: func(err error) error {\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn errors.New(\"got nil err\")\n\t\t\t\t}\n\n\t\t\t\tfound := regexp.MustCompile(`got nil/empty layouts slice`).Match([]byte(err.Error()))\n\t\t\t\tif !found {\n\t\t\t\t\treturn fmt.Errorf(\"given error does not satisfy pattern: %w\", err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t}\n\n\t// TODO: replace with maps.Keys() (go >= ), lo.Keys() if acceptable\n\tgetKeys := func(m map[string]time.Duration) []string {\n\t\tif m == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tkeys := make([]string, 0, len(m))\n\t\tfor k := range m {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\treturn keys\n\t}\n\n\tfor idx := range testCases {\n\t\ttestCase := testCases[idx]\n\t\tt.Run(testCase.caseName, func(t *testing.T) {\n\t\t\t// t.Parallel()\n\t\t\tfl := TimestampFlag{\n\t\t\t\tName: \"time\",\n\t\t\t\tConfig: TimestampConfig{\n\t\t\t\t\tLayouts: getKeys(testCase.layoutsPrecisions),\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tif len(testCase.layoutsPrecisions) == 0 {\n\t\t\t\terr := fl.Set(fl.Name, now.Format(time.RFC3339))\n\t\t\t\tif testCase.expErrValidation != nil {\n\t\t\t\t\tassert.NoError(t, testCase.expErrValidation(err))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvalidLayouts := make([]string, 0, len(testCase.layoutsPrecisions))\n\t\t\tinvalidLayouts := make([]string, 0, len(testCase.layoutsPrecisions))\n\n\t\t\t// TODO: replace with lo.Filter if acceptable\n\t\t\tfor layout, prec := range testCase.layoutsPrecisions {\n\t\t\t\tv, err := time.Parse(layout, now.Format(layout))\n\t\t\t\tif err != nil || prec == 0 || now.Truncate(prec).UnixNano() != v.Truncate(prec).UnixNano() {\n\t\t\t\t\tinvalidLayouts = append(invalidLayouts, layout)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalidLayouts = append(validLayouts, layout)\n\t\t\t}\n\n\t\t\tfor _, layout := range validLayouts {\n\t\t\t\terr := fl.Set(fl.Name, now.Format(layout))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tif !testCase.expRes.IsZero() {\n\t\t\t\t\tassert.Equal(t, testCase.expRes, fl.value.Get())\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor range invalidLayouts {\n\t\t\t\terr := fl.Set(fl.Name, now.Format(time.RFC3339))\n\t\t\t\tif testCase.expErrValidation != nil {\n\t\t\t\t\tassert.NoError(t, testCase.expErrValidation(err))\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestTimestampFlagApply_ShortenedLayouts(t *testing.T) {\n\tnow := time.Now().UTC()\n\n\tshortenedLayoutsPrecisions := map[string]time.Duration{\n\t\ttime.Kitchen:    time.Minute,\n\t\ttime.Stamp:      time.Second,\n\t\ttime.StampMilli: time.Millisecond,\n\t\ttime.StampMicro: time.Microsecond,\n\t\ttime.StampNano:  time.Nanosecond,\n\t\ttime.TimeOnly:   time.Second,\n\t\t\"15:04\":         time.Minute,\n\t}\n\n\t// TODO: replace with maps.Keys() (go >= ), lo.Keys() if acceptable\n\tgetKeys := func(m map[string]time.Duration) []string {\n\t\tif m == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tkeys := make([]string, 0, len(m))\n\t\tfor k := range m {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\treturn keys\n\t}\n\n\tfl := TimestampFlag{\n\t\tName: \"time\",\n\t\tConfig: TimestampConfig{\n\t\t\tLayouts: getKeys(shortenedLayoutsPrecisions),\n\t\t},\n\t}\n\n\tfor layout, prec := range shortenedLayoutsPrecisions {\n\t\terr := fl.Set(fl.Name, now.Format(layout))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, now.Truncate(prec), fl.value.Get())\n\t}\n}\n\nfunc TestTimestampFlagApplyValue(t *testing.T) {\n\texpectedResult, _ := time.Parse(time.RFC3339, \"2006-01-02T15:04:05Z\")\n\tfl := TimestampFlag{Name: \"time\", Aliases: []string{\"t\"}, Config: TimestampConfig{Layouts: []string{time.RFC3339}}, Value: expectedResult}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, expectedResult, cmd.Value(\"time\"))\n}\n\nfunc TestTimestampFlagApply_Fail_Parse_Wrong_Layout(t *testing.T) {\n\tfl := TimestampFlag{Name: \"time\", Aliases: []string{\"t\"}, Config: TimestampConfig{Layouts: []string{\"randomlayout\"}}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"\", \"--time\", \"2006-01-02T15:04:05Z\"})\n\tassert.EqualError(t, err, \"invalid value \\\"2006-01-02T15:04:05Z\\\" for flag -time: parsing time \\\"2006-01-02T15:04:05Z\\\" as \\\"randomlayout\\\": cannot parse \\\"2006-01-02T15:04:05Z\\\" as \\\"randomlayout\\\"\")\n}\n\nfunc TestTimestampFlagApply_Fail_Parse_Wrong_Time(t *testing.T) {\n\tfl := TimestampFlag{Name: \"time\", Aliases: []string{\"t\"}, Config: TimestampConfig{Layouts: []string{\"Jan 2, 2006 at 3:04pm (MST)\"}}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\terr := cmd.Set(\"time\", \"2006-01-02T15:04:05Z\")\n\tassert.EqualError(t, err, \"parsing time \\\"2006-01-02T15:04:05Z\\\" as \\\"Jan 2, 2006 at 3:04pm (MST)\\\": cannot parse \\\"2006-01-02T15:04:05Z\\\" as \\\"Jan\\\"\")\n}\n\nfunc TestTimestampFlagApply_Timezoned(t *testing.T) {\n\tpdt := time.FixedZone(\"PDT\", -7*60*60)\n\texpectedResult, _ := time.Parse(time.RFC3339, \"2006-01-02T15:04:05Z\")\n\tfl := TimestampFlag{Name: \"time\", Aliases: []string{\"t\"}, Config: TimestampConfig{Layouts: []string{time.ANSIC}, Timezone: pdt}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--time\", \"Mon Jan 2 08:04:05 2006\"}))\n\tassert.Equal(t, expectedResult.In(pdt), cmd.Value(\"time\"))\n}\n\nfunc TestTimestampFlagValueFromCommand(t *testing.T) {\n\tnow := time.Now()\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&TimestampFlag{\n\t\t\t\tName:  \"myflag\",\n\t\t\t\tValue: now,\n\t\t\t},\n\t\t},\n\t}\n\tf := &TimestampFlag{Name: \"myflag\"}\n\trequire.Equal(t, now, cmd.Timestamp(f.Name))\n}\n\ntype flagDefaultTestCase struct {\n\tname    string\n\tflag    Flag\n\ttoParse []string\n\texpect  string\n}\n\nfunc TestFlagDefaultValue(t *testing.T) {\n\tcases := []*flagDefaultTestCase{\n\t\t{\n\t\t\tname:    \"stringSlice\",\n\t\t\tflag:    &StringSliceFlag{Name: \"flag\", Value: []string{\"default1\", \"default2\"}},\n\t\t\ttoParse: []string{\"--flag\", \"parsed\"},\n\t\t\texpect:  `--flag string [ --flag string ]\t(default: \"default1\", \"default2\")`,\n\t\t},\n\t\t{\n\t\t\tname:    \"floatSlice\",\n\t\t\tflag:    &FloatSliceFlag{Name: \"flag\", Value: []float64{1.1, 2.2}},\n\t\t\ttoParse: []string{\"--flag\", \"13.3\"},\n\t\t\texpect:  `--flag float [ --flag float ]\t(default: 1.1, 2.2)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"float32Slice\",\n\t\t\tflag:    &Float32SliceFlag{Name: \"flag\", Value: []float32{1.1, 2.2}},\n\t\t\ttoParse: []string{\"--flag\", \"13.3\"},\n\t\t\texpect:  `--flag float [ --flag float ]\t(default: 1.1, 2.2)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"float64Slice\",\n\t\t\tflag:    &Float64SliceFlag{Name: \"flag\", Value: []float64{1.1, 2.2}},\n\t\t\ttoParse: []string{\"--flag\", \"13.3\"},\n\t\t\texpect:  `--flag float [ --flag float ]\t(default: 1.1, 2.2)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"intSlice\",\n\t\t\tflag:    &Int64SliceFlag{Name: \"flag\", Value: []int64{1, 2}},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag int [ --flag int ]\t(default: 1, 2)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"uintSlice\",\n\t\t\tflag:    &Uint64SliceFlag{Name: \"flag\", Value: []uint64{1, 2}},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag uint [ --flag uint ]\t(default: 1, 2)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"string\",\n\t\t\tflag:    &StringFlag{Name: \"flag\", Value: \"default\"},\n\t\t\ttoParse: []string{\"--flag\", \"parsed\"},\n\t\t\texpect:  `--flag string\t(default: \"default\")`,\n\t\t},\n\t\t{\n\t\t\tname:    \"bool\",\n\t\t\tflag:    &BoolFlag{Name: \"flag\", Value: true},\n\t\t\ttoParse: []string{\"--flag=false\"},\n\t\t\texpect:  `--flag\t`,\n\t\t},\n\t\t{\n\t\t\tname:    \"uint\",\n\t\t\tflag:    &UintFlag{Name: \"flag\", Value: 1},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag uint\t(default: 1)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"uint64\",\n\t\t\tflag:    &Uint64Flag{Name: \"flag\", Value: 1},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag uint\t(default: 1)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"stringMap\",\n\t\t\tflag:    &StringMapFlag{Name: \"flag\", Value: map[string]string{\"default1\": \"default2\"}},\n\t\t\ttoParse: []string{\"--flag\", \"parsed=\"},\n\t\t\texpect:  `--flag string=string [ --flag string=string ]\t(default: default1=\"default2\")`,\n\t\t},\n\t}\n\tfor _, v := range cases {\n\t\tt.Run(v.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\tv.flag,\n\t\t\t\t},\n\t\t\t}\n\t\t\tassert.NoError(t, cmd.Run(buildTestContext(t), append([]string{\"\"}, v.toParse...)))\n\t\t\tassert.Equal(t, v.expect, v.flag.String())\n\t\t})\n\t}\n}\n\ntype flagDefaultTestCaseWithEnv struct {\n\tname    string\n\tflag    Flag\n\ttoParse []string\n\texpect  string\n\tenviron map[string]string\n}\n\nfunc TestFlagDefaultValueWithEnv(t *testing.T) {\n\tts, err := time.Parse(time.RFC3339, \"2005-01-02T15:04:05Z\")\n\trequire.NoError(t, err)\n\tcases := []*flagDefaultTestCaseWithEnv{\n\t\t{\n\t\t\tname:    \"stringSlice\",\n\t\t\tflag:    &StringSliceFlag{Name: \"flag\", Value: []string{\"default1\", \"default2\"}, Sources: EnvVars(\"ssflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"parsed\"},\n\t\t\texpect:  `--flag string [ --flag string ]\t(default: \"default1\", \"default2\")` + withEnvHint([]string{\"ssflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"ssflag\": \"some-other-env_value\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"float64Slice\",\n\t\t\tflag:    &FloatSliceFlag{Name: \"flag\", Value: []float64{1.1, 2.2}, Sources: EnvVars(\"fsflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13.3\"},\n\t\t\texpect:  `--flag float [ --flag float ]\t(default: 1.1, 2.2)` + withEnvHint([]string{\"fsflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"fsflag\": \"20304.222\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"intSlice\",\n\t\t\tflag:    &Int64SliceFlag{Name: \"flag\", Value: []int64{1, 2}, Sources: EnvVars(\"isflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag int [ --flag int ]\t(default: 1, 2)` + withEnvHint([]string{\"isflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"isflag\": \"101\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"uintSlice\",\n\t\t\tflag:    &Uint64SliceFlag{Name: \"flag\", Value: []uint64{1, 2}, Sources: EnvVars(\"uisflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag uint [ --flag uint ]\t(default: 1, 2)` + withEnvHint([]string{\"uisflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uisflag\": \"3\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"string\",\n\t\t\tflag:    &StringFlag{Name: \"flag\", Value: \"default\", Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"parsed\"},\n\t\t\texpect:  `--flag string\t(default: \"default\")` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"some-other-string\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"bool\",\n\t\t\tflag:    &BoolFlag{Name: \"flag\", Value: true, Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag=false\"},\n\t\t\texpect:  `--flag\t` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"false\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"bool\",\n\t\t\tflag:   &BoolWithInverseFlag{Name: \"flag\", Value: true, Sources: EnvVars(\"uflag\")},\n\t\t\texpect: `--[no-]flag\t(default: true)` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"false\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"uint64\",\n\t\t\tflag:    &Uint64Flag{Name: \"flag\", Value: 1, Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag uint\t(default: 1)` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"10\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"uint\",\n\t\t\tflag:    &Uint64Flag{Name: \"flag\", Value: 1, Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag uint\t(default: 1)` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"10\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"int64\",\n\t\t\tflag:    &Int64Flag{Name: \"flag\", Value: 1, Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag int\t(default: 1)` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"10\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"int\",\n\t\t\tflag:    &Int64Flag{Name: \"flag\", Value: 1, Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"13\"},\n\t\t\texpect:  `--flag int\t(default: 1)` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"10\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"duration\",\n\t\t\tflag:    &DurationFlag{Name: \"flag\", Value: time.Second, Sources: EnvVars(\"uflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"2m\"},\n\t\t\texpect:  `--flag duration\t(default: 1s)` + withEnvHint([]string{\"uflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"uflag\": \"2h4m10s\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"timestamp\",\n\t\t\tflag:    &TimestampFlag{Name: \"flag\", Value: ts, Config: TimestampConfig{Layouts: []string{time.RFC3339}}, Sources: EnvVars(\"tflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"2006-11-02T15:04:05Z\"},\n\t\t\texpect:  `--flag time\t(default: 2005-01-02 15:04:05 +0000 UTC)` + withEnvHint([]string{\"tflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"tflag\": \"2010-01-02T15:04:05Z\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"stringMap\",\n\t\t\tflag:    &StringMapFlag{Name: \"flag\", Value: map[string]string{\"default1\": \"default2\"}, Sources: EnvVars(\"ssflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"parsed=\"},\n\t\t\texpect:  `--flag string=string [ --flag string=string ]\t(default: default1=\"default2\")` + withEnvHint([]string{\"ssflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"ssflag\": \"some-other-env_value=\",\n\t\t\t},\n\t\t},\n\t\t// TODO\n\t\t/*{\n\t\t\tname:    \"generic\",\n\t\t\tflag:    &GenericFlag{Name: \"flag\", Value: &Parser{\"11\", \"12\"}, Sources: EnvVars(\"gflag\")},\n\t\t\ttoParse: []string{\"--flag\", \"15,16\"},\n\t\t\texpect:  `--flag value\t(default: 11,12)` + withEnvHint([]string{\"gflag\"}, \"\"),\n\t\t\tenviron: map[string]string{\n\t\t\t\t\"gflag\": \"13,14\",\n\t\t\t},\n\t\t},*/\n\t}\n\tfor _, v := range cases {\n\t\tt.Run(v.name, func(t *testing.T) {\n\t\t\tfor key, val := range v.environ {\n\t\t\t\tt.Setenv(key, val)\n\t\t\t}\n\t\t\tcmd := &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\tv.flag,\n\t\t\t\t},\n\t\t\t}\n\t\t\trequire.NoError(t, cmd.Run(buildTestContext(t), append([]string{\"\"}, v.toParse...)))\n\t\t\tassert.Equal(t, v.expect, v.flag.String())\n\t\t})\n\t}\n}\n\ntype flagValueTestCase struct {\n\tname    string\n\tflag    Flag\n\ttoParse []string\n\texpect  string\n}\n\nfunc TestFlagValue(t *testing.T) {\n\tt.SkipNow()\n\tcases := []*flagValueTestCase{\n\t\t{\n\t\t\tname:    \"stringSlice\",\n\t\t\tflag:    &StringSliceFlag{Name: \"flag\", Value: []string{\"default1\", \"default2\"}},\n\t\t\ttoParse: []string{\"--flag\", \"parsed,parsed2\", \"--flag\", \"parsed3,parsed4\"},\n\t\t\texpect:  `[parsed parsed2 parsed3 parsed4]`,\n\t\t},\n\t\t{\n\t\t\tname:    \"float64Slice\",\n\t\t\tflag:    &FloatSliceFlag{Name: \"flag\", Value: []float64{1.1, 2.2}},\n\t\t\ttoParse: []string{\"--flag\", \"13.3,14.4\", \"--flag\", \"15.5,16.6\"},\n\t\t\texpect:  `[]float64{13.3, 14.4, 15.5, 16.6}`,\n\t\t},\n\t\t{\n\t\t\tname:    \"intSlice\",\n\t\t\tflag:    &Int64SliceFlag{Name: \"flag\", Value: []int64{1, 2}},\n\t\t\ttoParse: []string{\"--flag\", \"13,14\", \"--flag\", \"15,16\"},\n\t\t\texpect:  `[]int64{13, 14, 15, 16}`,\n\t\t},\n\t\t{\n\t\t\tname:    \"uintSlice\",\n\t\t\tflag:    &Uint64SliceFlag{Name: \"flag\", Value: []uint64{1, 2}},\n\t\t\ttoParse: []string{\"--flag\", \"13,14\", \"--flag\", \"15,16\"},\n\t\t\texpect:  `[]uint64{13, 14, 15, 16}`,\n\t\t},\n\t\t{\n\t\t\tname:    \"stringMap\",\n\t\t\tflag:    &StringMapFlag{Name: \"flag\", Value: map[string]string{\"default1\": \"default2\"}},\n\t\t\ttoParse: []string{\"--flag\", \"parsed=parsed2\", \"--flag\", \"parsed3=parsed4\"},\n\t\t\texpect:  `map[parsed:parsed2 parsed3:parsed4]`,\n\t\t},\n\t\t{\n\t\t\tname:    \"int\",\n\t\t\tflag:    &IntFlag{Name: \"flag\", Value: 1},\n\t\t\ttoParse: []string{\"--flag\", \"42\"},\n\t\t\texpect:  `int(42)`,\n\t\t},\n\t\t{\n\t\t\tname:    \"uint\",\n\t\t\tflag:    &UintFlag{Name: \"flag\", Value: 1},\n\t\t\ttoParse: []string{\"--flag\", \"42\"},\n\t\t\texpect:  `uint(42)`,\n\t\t},\n\t}\n\tfor _, v := range cases {\n\t\tt.Run(v.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\tv.flag,\n\t\t\t\t},\n\t\t\t}\n\t\t\tassert.NoError(t, cmd.Run(buildTestContext(t), append([]string{\"\"}, v.toParse...)))\n\t\t\tf := cmd.lookupFlag(\"flag\")\n\t\t\trequire.Equal(t, v.expect, f.String())\n\t\t})\n\t}\n}\n\nfunc TestTimestampFlagApply_WithDestination(t *testing.T) {\n\tvar destination time.Time\n\texpectedResult, _ := time.Parse(time.RFC3339, \"2006-01-02T15:04:05Z\")\n\tfl := TimestampFlag{Name: \"time\", Aliases: []string{\"t\"}, Config: TimestampConfig{Layouts: []string{time.RFC3339}}, Destination: &destination}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--time\", \"2006-01-02T15:04:05Z\"}))\n\tassert.Equal(t, expectedResult, destination)\n}\n\n// Test issue #1254\n// StringSlice() with UseShortOptionHandling causes duplicated entries, depending on the ordering of the flags\nfunc TestSliceShortOptionHandle(t *testing.T) {\n\twasCalled := false\n\terr := (&Command{\n\t\tName:                   \"foobar\",\n\t\tUseShortOptionHandling: true,\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\twasCalled = true\n\n\t\t\tif !cmd.Bool(\"i\") {\n\t\t\t\treturn fmt.Errorf(\"bool i not set\")\n\t\t\t}\n\n\t\t\tif !cmd.Bool(\"t\") {\n\t\t\t\treturn fmt.Errorf(\"bool i not set\")\n\t\t\t}\n\n\t\t\tss := cmd.StringSlice(\"net\")\n\t\t\tif !reflect.DeepEqual(ss, []string{\"foo\"}) {\n\t\t\t\treturn fmt.Errorf(\"got different slice %q than expected\", ss)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\tFlags: []Flag{\n\t\t\t&StringSliceFlag{Name: \"net\"},\n\t\t\t&BoolFlag{Name: \"i\"},\n\t\t\t&BoolFlag{Name: \"t\"},\n\t\t},\n\t}).Run(buildTestContext(t), []string{\"foobar\", \"--net=foo\", \"-it\"})\n\n\tr := require.New(t)\n\n\tr.NoError(err)\n\tr.Truef(wasCalled, \"action callback was never called\")\n}\n\n// Test issue #1541\nfunc TestCustomizedSliceFlagSeparator(t *testing.T) {\n\topts := []string{\"opt1\", \"opt2\", \"opt3,op\", \"opt4\"}\n\tret := flagSplitMultiValues(strings.Join(opts, \";\"), \";\", disableSliceFlagSeparator)\n\trequire.Equal(t, 4, len(ret), \"split slice flag failed\")\n\tfor idx, r := range ret {\n\t\trequire.Equal(t, opts[idx], r, \"get %dth failed\", idx)\n\t}\n}\n\nfunc TestFlagSplitMultiValues_Disabled(t *testing.T) {\n\topts := []string{\"opt1\", \"opt2\", \"opt3,op\", \"opt4\"}\n\tret := flagSplitMultiValues(strings.Join(opts, defaultSliceFlagSeparator), defaultSliceFlagSeparator, true)\n\trequire.Equal(t, 1, len(ret), \"failed to disable split slice flag\")\n\trequire.Equal(t, strings.Join(opts, defaultSliceFlagSeparator), ret[0])\n}\n\nvar stringMapFlagTests = []struct {\n\tname     string\n\taliases  []string\n\tvalue    map[string]string\n\texpected string\n}{\n\t{\"foo\", nil, nil, \"--foo string=string [ --foo string=string ]\\t\"},\n\t{\"f\", nil, nil, \"-f string=string [ -f string=string ]\\t\"},\n\t{\"f\", nil, map[string]string{\"Lipstick\": \"\"}, \"-f string=string [ -f string=string ]\\t(default: Lipstick=)\"},\n\t{\"test\", nil, map[string]string{\"Something\": \"\"}, \"--test string=string [ --test string=string ]\\t(default: Something=)\"},\n\t{\"dee\", []string{\"d\"}, map[string]string{\"Inka\": \"Dinka\", \"dooo\": \"\"}, \"--dee string=string, -d string=string [ --dee string=string, -d string=string ]\\t(default: Inka=\\\"Dinka\\\", dooo=)\"},\n}\n\nfunc TestStringMapFlagHelpOutput(t *testing.T) {\n\tfor _, test := range stringMapFlagTests {\n\t\tf := &StringMapFlag{Name: test.name, Aliases: test.aliases, Value: test.value}\n\t\tassert.Equal(t, test.expected, f.String())\n\t}\n}\n\nfunc TestStringMapFlagWithEnvVarHelpOutput(t *testing.T) {\n\tt.Setenv(\"APP_QWWX\", \"11,4\")\n\n\tfor _, test := range stringMapFlagTests {\n\t\tfl := &StringMapFlag{Name: test.name, Aliases: test.aliases, Value: test.value, Sources: EnvVars(\"APP_QWWX\")}\n\t\toutput := fl.String()\n\n\t\texpectedSuffix := withEnvHint([]string{\"APP_QWWX\"}, \"\")\n\t\tif !strings.HasSuffix(output, expectedSuffix) {\n\t\t\tt.Errorf(\"%q does not end with\"+expectedSuffix, output)\n\t\t}\n\t}\n}\n\nfunc TestStringMapFlagApply_SetsAllNames(t *testing.T) {\n\tfl := StringMapFlag{Name: \"goat\", Aliases: []string{\"G\", \"gooots\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--goat\", \"aaa=\", \"-G\", \"bbb=\", \"--gooots\", \"eeeee=\"}))\n}\n\nfunc TestStringMapFlagApply_UsesEnvValues_noDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"vincent van goat=scape goat\")\n\tvar val map[string]string\n\tfl := StringMapFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Nil(t, val)\n\tassert.Equal(t, map[string]string{\"vincent van goat\": \"scape goat\"}, cmd.Value(\"goat\"))\n}\n\nfunc TestStringMapFlagApply_UsesEnvValues_withDefault(t *testing.T) {\n\tt.Setenv(\"MY_GOAT\", \"vincent van goat=scape goat\")\n\tval := map[string]string{`some default`: `values here`}\n\tfl := StringMapFlag{Name: \"goat\", Sources: EnvVars(\"MY_GOAT\"), Value: val}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, map[string]string{`some default`: `values here`}, val)\n\tassert.Equal(t, map[string]string{\"vincent van goat\": \"scape goat\"}, cmd.Value(\"goat\"))\n}\n\nfunc TestStringMapFlagApply_DefaultValueWithDestination(t *testing.T) {\n\tdefValue := map[string]string{\"UA\": \"US\"}\n\n\tfl := StringMapFlag{Name: \"country\", Value: defValue, Destination: &map[string]string{\"CA\": \"\"}}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\tassert.Equal(t, defValue, *fl.Destination)\n}\n\nfunc TestStringMapFlagValueFromCommand(t *testing.T) {\n\tf := &StringMapFlag{Name: \"myflag\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\tf,\n\t\t},\n\t}\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\"}))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"a=b\"))\n\trequire.NoError(t, cmd.Set(\"myflag\", \"c=\"))\n\n\trequire.Equal(t, map[string]string{\"a\": \"b\", \"c\": \"\"}, cmd.StringMap(f.Name))\n}\n\nfunc TestStringMapFlagApply_Error(t *testing.T) {\n\tfl := StringMapFlag{Name: \"goat\"}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&fl,\n\t\t},\n\t}\n\n\tassert.Error(t, cmd.Run(buildTestContext(t), []string{\"\", \"--goat\", \"aaa\", \"bbb=\"}))\n}\n\nfunc TestZeroValueMutexFlag(t *testing.T) {\n\tvar fl MutuallyExclusiveFlags\n\tassert.NoError(t, fl.check(&Command{}))\n}\n\nfunc TestMutexFlagCategory(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.Category = \"TestCmd\"\n\tcmd.MutuallyExclusiveFlags = []MutuallyExclusiveFlags{\n\t\t{\n\t\t\tFlags: [][]Flag{\n\t\t\t\t{\n\t\t\t\t\t&StringFlag{Name: \"foo\", Category: \"Group1\"},\n\t\t\t\t\t&IntFlag{Name: \"bar\", Category: \"Group1\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t&StringFlag{Name: \"baz\", Category: \"Group2\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tassert.NoError(t, cmd.Run(buildTestContext(t), []string{\"\", \"--foo\", \"value\"}))\n}\n\nfunc TestExtFlag(t *testing.T) {\n\tvar iv intValue[int64]\n\tvar ipv int64\n\n\tf := &flag.Flag{\n\t\tName:     \"bar\",\n\t\tUsage:    \"bar usage\",\n\t\tValue:    iv.Create(11, &ipv, IntegerConfig{}),\n\t\tDefValue: \"10\",\n\t}\n\n\textF := &extFlag{\n\t\tf: f,\n\t}\n\n\tassert.Equal(t, []string{\"bar\"}, extF.Names())\n\tassert.True(t, extF.IsVisible())\n\tassert.False(t, extF.IsSet())\n\tassert.False(t, extF.TakesValue())\n\tassert.Equal(t, \"bar usage\", extF.GetUsage())\n\tassert.Equal(t, \"11\", extF.GetValue())\n\tassert.Equal(t, \"10\", extF.GetDefaultText())\n\tassert.Nil(t, extF.GetEnvVars())\n}\n\nfunc TestSliceValuesNil(t *testing.T) {\n\tassert.Equal(t, []float64(nil), NewFloatSlice().Value())\n\tassert.Equal(t, []float32(nil), NewFloat32Slice().Value())\n\tassert.Equal(t, []float64(nil), NewFloat64Slice().Value())\n\tassert.Equal(t, []int64(nil), NewInt64Slice().Value())\n\tassert.Equal(t, []uint64(nil), NewUint64Slice().Value())\n\tassert.Equal(t, []string(nil), NewStringSlice().Value())\n\n\tassert.Equal(t, []float64(nil), (&FloatSlice{}).Value())\n\tassert.Equal(t, []float32(nil), (&Float32Slice{}).Value())\n\tassert.Equal(t, []float64(nil), (&Float64Slice{}).Value())\n\tassert.Equal(t, []int64(nil), (&Int64Slice{}).Value())\n\tassert.Equal(t, []uint64(nil), (&Uint64Slice{}).Value())\n\tassert.Equal(t, []string(nil), (&StringSlice{}).Value())\n}\n\nfunc TestFileHint(t *testing.T) {\n\tassert.Equal(t, \"\", withFileHint(\"\", \"\"))\n\tassert.Equal(t, \" [/tmp/foo.txt]\", withFileHint(\"/tmp/foo.txt\", \"\"))\n\tassert.Equal(t, \"foo\", withFileHint(\"\", \"foo\"))\n\tassert.Equal(t, \"bar [/tmp/foo.txt]\", withFileHint(\"/tmp/foo.txt\", \"bar\"))\n}\n\nfunc TestHasFlags(t *testing.T) {\n\tflagToCheck := &StringFlag{Name: \"foo\"}\n\tflags := []Flag{\n\t\t&StringFlag{Name: \"bar\"},\n\t\t&Int64Flag{Name: \"baz\"},\n\t\tflagToCheck,\n\t}\n\n\tassert.True(t, hasFlag(flags, flagToCheck))\n}\n\nfunc TestFlagsByName(t *testing.T) {\n\tflags := []Flag{\n\t\t&StringFlag{\n\t\t\tName: \"b2\",\n\t\t},\n\t\t&Int64Flag{\n\t\t\tName: \"a0\",\n\t\t},\n\t\t&FloatFlag{\n\t\t\tName: \"b1\",\n\t\t},\n\t}\n\n\tflagsByName := FlagsByName(flags)\n\tsort.Sort(flagsByName)\n\n\tassert.Equal(t, len(flags), flagsByName.Len())\n\n\tvar prev Flag\n\tfor _, f := range flags {\n\t\tif prev != nil {\n\t\t\tassert.LessOrEqual(t, prev.Names()[0], f.Names()[0])\n\t\t}\n\t\tprev = f\n\t}\n}\n\nfunc TestNonStringMap(t *testing.T) {\n\ttype (\n\t\tfloatMap = MapBase[float64, NoConfig, floatValue[float64]]\n\t)\n\n\tp := map[string]float64{}\n\n\tvar fv floatValue[float64]\n\n\tf := &floatMap{\n\t\tvalue: &fv,\n\t}\n\n\tassert.Equal(t, map[string]float64{}, f.Value())\n\tf.dict = &p\n\tassert.Equal(t, map[string]float64{}, f.Value())\n\tassert.Equal(t, \"map[string]float64{}\", f.String())\n\n\tassert.ErrorContains(t, f.Set(\"invalid=value\"), \"ParseFloat\")\n}\n\nfunc TestUnquoteUsage(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpStr   string\n\t\texpUsage string\n\t}{\n\t\t{\"foo\", \"\", \"foo\"},\n\t\t{\"foo something\", \"\", \"foo something\"},\n\t\t{\"foo `bar 11`\", \"bar 11\", \"foo bar 11\"},\n\t\t{\"foo `bar 11` sobar\", \"bar 11\", \"foo bar 11 sobar\"},\n\t\t{\"foo `bar 11\", \"\", \"foo `bar 11\"},\n\t}\n\n\tfor i, test := range tests {\n\t\tt.Run(fmt.Sprintf(\"unquote %d\", i), func(t *testing.T) {\n\t\t\tstr, usage := unquoteUsage(test.str)\n\t\t\tassert.Equal(t, test.expStr, str)\n\t\t\tassert.Equal(t, test.expUsage, usage)\n\t\t})\n\t}\n}\n\nfunc TestEnvHintWindows(t *testing.T) {\n\tif runtime.GOOS == \"windows\" && os.Getenv(\"PSHOME\") == \"\" {\n\t\tassert.Equal(t, \"something [%foo%, %bar%, %ss%]\", withEnvHint([]string{\"foo\", \"bar\", \"ss\"}, \"something\"))\n\t}\n}\n\nfunc TestDocGetValue(t *testing.T) {\n\tassert.Equal(t, \"true\", (&BoolFlag{Name: \"foo\", Value: true}).GetValue())\n\tassert.Equal(t, \"false\", (&BoolFlag{Name: \"foo\", Value: false}).GetValue())\n\tassert.Equal(t, \"\\\"bar\\\"\", (&StringFlag{Name: \"foo\", Value: \"bar\"}).GetValue())\n\tassert.Equal(t, \"\", (&BoolWithInverseFlag{Name: \"foo\", Value: false}).GetValue())\n}\n\nfunc TestGenericFlag_SatisfiesFlagInterface(t *testing.T) {\n\tvar f Flag = &GenericFlag{}\n\n\t_ = f.IsSet()\n\t_ = f.Names()\n}\n\nfunc TestGenericValue_SatisfiesBoolInterface(t *testing.T) {\n\tvar f boolFlag = &genericValue{}\n\tvar fpv float64\n\n\tassert.False(t, f.IsBoolFlag())\n\n\tfv := floatValue[float64]{val: &fpv}\n\tf = &genericValue{\n\t\tval: &fv,\n\t}\n\n\tassert.False(t, f.IsBoolFlag())\n\n\tf = &genericValue{\n\t\tval: &boolValue{},\n\t}\n\tassert.True(t, f.IsBoolFlag())\n}\n\nfunc TestGenericFlag_SatisfiesFmtStringerInterface(t *testing.T) {\n\tvar f fmt.Stringer = &GenericFlag{}\n\n\t_ = f.String()\n}\n\nfunc TestGenericFlag_SatisfiesRequiredFlagInterface(t *testing.T) {\n\tvar f RequiredFlag = &GenericFlag{}\n\n\t_ = f.IsRequired()\n}\n\nfunc TestGenericFlag_SatisfiesVisibleFlagInterface(t *testing.T) {\n\tvar f VisibleFlag = &GenericFlag{}\n\n\t_ = f.IsVisible()\n}\n\nfunc TestGenericFlag_SatisfiesDocFlagInterface(t *testing.T) {\n\tvar f DocGenerationFlag = &GenericFlag{}\n\n\t_ = f.GetUsage()\n}\n\nfunc TestGenericValue(t *testing.T) {\n\tg := &genericValue{}\n\tassert.NoError(t, g.Set(\"something\"))\n\tassert.Nil(t, g.Get())\n\tassert.Empty(t, g.String())\n}\n\nfunc TestEndValue(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.UseShortOptionHandling = true\n\tcmd.Flags = []Flag{\n\t\t&IntFlag{Name: \"debug\", Aliases: []string{\"d\"}},\n\t\t&IntFlag{Name: \"count\", Aliases: []string{\"c\"}},\n\t}\n\n\tassert.Error(t, cmd.Run(buildTestContext(t), []string{\"foo\", \"-cd=\"}))\n\tassert.Error(t, cmd.Run(buildTestContext(t), []string{\"foo\", \"-cd=s\"}))\n}\n"
  },
  {
    "path": "flag_timestamp.go",
    "content": "package cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n)\n\ntype TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampValue]\n\n// TimestampConfig defines the config for timestamp flags\ntype TimestampConfig struct {\n\tTimezone *time.Location\n\t// Available layouts for flag value.\n\t//\n\t// Note that value for formats with missing year/date will be interpreted as current year/date respectively.\n\t//\n\t// Read more about time layouts: https://pkg.go.dev/time#pkg-constants\n\tLayouts []string\n}\n\n// timestampValue wrap to satisfy golang's flag interface.\ntype timestampValue struct {\n\ttimestamp  *time.Time\n\thasBeenSet bool\n\tlayouts    []string\n\tlocation   *time.Location\n}\n\nvar _ ValueCreator[time.Time, TimestampConfig] = timestampValue{}\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (t timestampValue) Create(val time.Time, p *time.Time, c TimestampConfig) Value {\n\t*p = val\n\treturn &timestampValue{\n\t\ttimestamp: p,\n\t\tlayouts:   c.Layouts,\n\t\tlocation:  c.Timezone,\n\t}\n}\n\nfunc (t timestampValue) ToString(b time.Time) string {\n\tif b.IsZero() {\n\t\treturn \"\"\n\t}\n\tt.timestamp = &b\n\treturn t.String()\n}\n\n// Below functions are to satisfy the Value interface\n\n// Parses the string value to timestamp\nfunc (t *timestampValue) Set(value string) error {\n\tvar timestamp time.Time\n\tvar err error\n\n\tif t.location == nil {\n\t\tt.location = time.UTC\n\t}\n\n\tif len(t.layouts) == 0 {\n\t\treturn errors.New(\"got nil/empty layouts slice\")\n\t}\n\n\tfor _, layout := range t.layouts {\n\t\tvar locErr error\n\n\t\ttimestamp, locErr = time.ParseInLocation(layout, value, t.location)\n\t\tif locErr != nil {\n\t\t\tif err == nil {\n\t\t\t\terr = locErr\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr = newMultiError(err, locErr)\n\t\t\tcontinue\n\t\t}\n\n\t\terr = nil\n\t\tbreak\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefaultTS, _ := time.ParseInLocation(time.TimeOnly, time.TimeOnly, timestamp.Location())\n\n\tn := time.Now().In(timestamp.Location())\n\n\t// If format is missing date (or year only), set it explicitly to current\n\tif timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() {\n\t\ttimestamp = time.Date(\n\t\t\tn.Year(),\n\t\t\tn.Month(),\n\t\t\tn.Day(),\n\t\t\ttimestamp.Hour(),\n\t\t\ttimestamp.Minute(),\n\t\t\ttimestamp.Second(),\n\t\t\ttimestamp.Nanosecond(),\n\t\t\ttimestamp.Location(),\n\t\t)\n\t} else if timestamp.Year() == 0 {\n\t\ttimestamp = time.Date(\n\t\t\tn.Year(),\n\t\t\ttimestamp.Month(),\n\t\t\ttimestamp.Day(),\n\t\t\ttimestamp.Hour(),\n\t\t\ttimestamp.Minute(),\n\t\t\ttimestamp.Second(),\n\t\t\ttimestamp.Nanosecond(),\n\t\t\ttimestamp.Location(),\n\t\t)\n\t}\n\n\tif t.timestamp != nil {\n\t\t*t.timestamp = timestamp\n\t}\n\tt.hasBeenSet = true\n\treturn nil\n}\n\n// String returns a readable representation of this value (for usage defaults)\nfunc (t *timestampValue) String() string {\n\treturn fmt.Sprintf(\"%v\", t.timestamp)\n}\n\n// Get returns the flag structure\nfunc (t *timestampValue) Get() any {\n\treturn *t.timestamp\n}\n\n// Timestamp gets the timestamp from a flag name\nfunc (cmd *Command) Timestamp(name string) time.Time {\n\tif v, ok := cmd.Value(name).(time.Time); ok {\n\t\ttracef(\"time.Time available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\t\treturn v\n\t}\n\n\ttracef(\"time.Time NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn time.Time{}\n}\n"
  },
  {
    "path": "flag_uint.go",
    "content": "package cli\n\nimport (\n\t\"strconv\"\n\t\"unsafe\"\n)\n\ntype (\n\tUintFlag   = FlagBase[uint, IntegerConfig, uintValue[uint]]\n\tUint8Flag  = FlagBase[uint8, IntegerConfig, uintValue[uint8]]\n\tUint16Flag = FlagBase[uint16, IntegerConfig, uintValue[uint16]]\n\tUint32Flag = FlagBase[uint32, IntegerConfig, uintValue[uint32]]\n\tUint64Flag = FlagBase[uint64, IntegerConfig, uintValue[uint64]]\n)\n\n// -- uint Value\ntype uintValue[T uint | uint8 | uint16 | uint32 | uint64] struct {\n\tval  *T\n\tbase int\n}\n\n// Below functions are to satisfy the ValueCreator interface\n\nfunc (i uintValue[T]) Create(val T, p *T, c IntegerConfig) Value {\n\t*p = val\n\n\treturn &uintValue[T]{\n\t\tval:  p,\n\t\tbase: c.Base,\n\t}\n}\n\nfunc (i uintValue[T]) ToString(b T) string {\n\ti.val = &b\n\treturn i.String()\n}\n\n// Below functions are to satisfy the flag.Value interface\n\nfunc (i *uintValue[T]) Set(s string) error {\n\tv, err := strconv.ParseUint(s, i.base, int(unsafe.Sizeof(T(0))*8))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*i.val = T(v)\n\treturn err\n}\n\nfunc (i *uintValue[T]) Get() any { return *i.val }\n\nfunc (i *uintValue[T]) String() string {\n\tbase := i.base\n\tif base == 0 {\n\t\tbase = 10\n\t}\n\n\treturn strconv.FormatUint(uint64(*i.val), base)\n}\n\n// Uint looks up the value of a local Uint64Flag, returns\n// 0 if not found\nfunc (cmd *Command) Uint(name string) uint {\n\treturn getUint[uint](cmd, name)\n}\n\n// Uint8 looks up the value of a local Uint8Flag, returns\n// 0 if not found\nfunc (cmd *Command) Uint8(name string) uint8 {\n\treturn getUint[uint8](cmd, name)\n}\n\n// Uint16 looks up the value of a local Uint16Flag, returns\n// 0 if not found\nfunc (cmd *Command) Uint16(name string) uint16 {\n\treturn getUint[uint16](cmd, name)\n}\n\n// Uint32 looks up the value of a local Uint32Flag, returns\n// 0 if not found\nfunc (cmd *Command) Uint32(name string) uint32 {\n\treturn getUint[uint32](cmd, name)\n}\n\n// Uint64 looks up the value of a local Uint64Flag, returns\n// 0 if not found\nfunc (cmd *Command) Uint64(name string) uint64 {\n\treturn getUint[uint64](cmd, name)\n}\n\nfunc getUint[T uint | uint8 | uint16 | uint32 | uint64](cmd *Command, name string) T {\n\tif v, ok := cmd.Value(name).(T); ok {\n\t\ttracef(\"uint available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\n\t\treturn v\n\t}\n\n\ttracef(\"uint NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn 0\n}\n"
  },
  {
    "path": "flag_uint_slice.go",
    "content": "package cli\n\ntype (\n\tUintSlice       = SliceBase[uint, IntegerConfig, uintValue[uint]]\n\tUint8Slice      = SliceBase[uint8, IntegerConfig, uintValue[uint8]]\n\tUint16Slice     = SliceBase[uint16, IntegerConfig, uintValue[uint16]]\n\tUint32Slice     = SliceBase[uint32, IntegerConfig, uintValue[uint32]]\n\tUint64Slice     = SliceBase[uint64, IntegerConfig, uintValue[uint64]]\n\tUintSliceFlag   = FlagBase[[]uint, IntegerConfig, UintSlice]\n\tUint8SliceFlag  = FlagBase[[]uint8, IntegerConfig, Uint8Slice]\n\tUint16SliceFlag = FlagBase[[]uint16, IntegerConfig, Uint16Slice]\n\tUint32SliceFlag = FlagBase[[]uint32, IntegerConfig, Uint32Slice]\n\tUint64SliceFlag = FlagBase[[]uint64, IntegerConfig, Uint64Slice]\n)\n\nvar (\n\tNewUintSlice   = NewSliceBase[uint, IntegerConfig, uintValue[uint]]\n\tNewUint8Slice  = NewSliceBase[uint8, IntegerConfig, uintValue[uint8]]\n\tNewUint16Slice = NewSliceBase[uint16, IntegerConfig, uintValue[uint16]]\n\tNewUint32Slice = NewSliceBase[uint32, IntegerConfig, uintValue[uint32]]\n\tNewUint64Slice = NewSliceBase[uint64, IntegerConfig, uintValue[uint64]]\n)\n\n// UintSlice looks up the value of a local UintSliceFlag, returns\n// nil if not found\nfunc (cmd *Command) UintSlice(name string) []uint {\n\treturn getUintSlice[uint](cmd, name)\n}\n\n// Uint8Slice looks up the value of a local Uint8SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Uint8Slice(name string) []uint8 {\n\treturn getUintSlice[uint8](cmd, name)\n}\n\n// Uint16Slice looks up the value of a local Uint16SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Uint16Slice(name string) []uint16 {\n\treturn getUintSlice[uint16](cmd, name)\n}\n\n// Uint32Slice looks up the value of a local Uint32SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Uint32Slice(name string) []uint32 {\n\treturn getUintSlice[uint32](cmd, name)\n}\n\n// Uint64Slice looks up the value of a local Uint64SliceFlag, returns\n// nil if not found\nfunc (cmd *Command) Uint64Slice(name string) []uint64 {\n\treturn getUintSlice[uint64](cmd, name)\n}\n\nfunc getUintSlice[T uint | uint8 | uint16 | uint32 | uint64](cmd *Command, name string) []T {\n\tif v, ok := cmd.Value(name).([]T); ok {\n\t\ttracef(\"uint slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)\", name, v, cmd.Name)\n\n\t\treturn v\n\t}\n\n\ttracef(\"uint slice NOT available for flag name %[1]q (cmd=%[2]q)\", name, cmd.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "flag_uint_slice_test.go",
    "content": "package cli\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCommand_UintSlice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []uint\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &UintSliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []uint{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &UintSliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []uint{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.UintSlice(name), \"UintSlice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Uint8Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []uint8\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Uint8SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []uint8{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Uint8SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []uint8{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Uint8Slice(name), \"Uint8Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Uint16Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []uint16\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Uint16SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []uint16{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Uint16SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []uint16{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Uint16Slice(name), \"Uint16Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Uint32Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []uint32\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Uint32SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []uint32{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Uint32SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []uint32{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Uint32Slice(name), \"Uint32Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommand_Uint64Slice(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tflag      Flag\n\t\targuments []string\n\t\texpect    []uint64\n\t\texpectErr bool\n\t}{\n\t\t{\n\t\t\tflag: &Uint64SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2,3,4\"},\n\t\t\texpect:    []uint64{1, 2, 3, 4},\n\t\t},\n\t\t{\n\t\t\tflag: &Uint64SliceFlag{\n\t\t\t\tName: \"numbers\",\n\t\t\t},\n\t\t\targuments: []string{\"--numbers\", \"1,2\", \"--numbers\", \"3,4\"},\n\t\t\texpect:    []uint64{1, 2, 3, 4},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equalf(t, tt.expect, cmd.Uint64Slice(name), \"Uint64Slice(%v)\", name)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "flag_uint_test.go",
    "content": "package cli\n\nimport (\n\t\"flag\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestUintFlag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue uint\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &UintFlag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"234567\"},\n\t\t\texpectedValue: 234567,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &UintFlag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Uint(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUint8Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue uint8\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Uint8Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"255\"},\n\t\t\texpectedValue: 255,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Uint8Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Uint8(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUint16Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue uint16\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Uint16Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"65535\"},\n\t\t\texpectedValue: 65535,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Uint16Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"out of range\",\n\t\t\tflag: &Uint16Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"65536\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Uint16(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUint32Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue uint32\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Uint32Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"2147483648\"},\n\t\t\texpectedValue: 2147483648,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Uint32Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"out of range\",\n\t\t\tflag: &Uint32Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"4294967297\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Uint32(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUint64Flag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          Flag\n\t\targuments     []string\n\t\texpectedValue uint64\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &Uint64Flag{\n\t\t\t\tName:    \"number\",\n\t\t\t\tAliases: []string{\"n\"},\n\t\t\t},\n\t\t\targuments:     []string{\"--number\", \"21474836480\"},\n\t\t\texpectedValue: 21474836480,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &Uint64Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{tt.flag},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, name := range tt.flag.Names() {\n\t\t\t\tassert.Equal(t, tt.expectedValue, cmd.Uint64(name))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUintFlagExt(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tflag          *flag.Flag\n\t\tconfig        IntegerConfig\n\t\targuments     []string\n\t\texpectedValue string\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{},\n\t\t\targuments:     []string{\"--number\", \"234567\"},\n\t\t\texpectedValue: \"234567\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{Base: 10},\n\t\t\targuments:     []string{\"--number\", \"234567\"},\n\t\t\texpectedValue: \"234567\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid hex\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{Base: 16},\n\t\t\targuments:     []string{\"--number\", \"39447\"},\n\t\t\texpectedValue: \"39447\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid hex default\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName:     \"number\",\n\t\t\t\tDefValue: \"FFFF\",\n\t\t\t},\n\t\t\tconfig:        IntegerConfig{Base: 16},\n\t\t\texpectedValue: \"ffff\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tflag: &flag.Flag{\n\t\t\t\tName: \"number\",\n\t\t\t},\n\t\t\targuments: []string{\"--number\", \"gopher\"},\n\t\t\texpectErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar uValue uintValue[uint]\n\t\t\tvar u uint\n\n\t\t\tf := &extFlag{f: tt.flag}\n\n\t\t\ttt.flag.Value = uValue.Create(u, &u, tt.config)\n\n\t\t\tcmd := &Command{\n\t\t\t\tName:      \"mock\",\n\t\t\t\tFlags:     []Flag{f},\n\t\t\t\tWriter:    io.Discard,\n\t\t\t\tErrWriter: io.Discard,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), append([]string{\"mock\"}, tt.arguments...))\n\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expectedValue, f.GetValue())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "flag_validation_test.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFlagDefaultValidation(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"foo\",\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{\n\t\t\t\tName:  \"if\",\n\t\t\t\tValue: 2, // this value should fail validation\n\t\t\t\tValidator: func(i int64) error {\n\t\t\t\t\tif (i >= 3 && i <= 10) || (i >= 20 && i <= 24) {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t\treturn fmt.Errorf(\"Value %d not in range [3,10] or [20,24]\", i)\n\t\t\t\t},\n\t\t\t\tValidateDefaults: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\t// this is a simple call to test PreParse failure before\n\t// parsing has been done\n\tr.Error(cmd.Set(\"if\", \"11\"))\n\n\t// Default value of flag is 2 which should fail validation\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--if\", \"5\"})\n\tr.Error(err)\n}\n\nfunc TestBoolInverseFlagDefaultValidation(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"foo\",\n\t\tFlags: []Flag{\n\t\t\t&BoolWithInverseFlag{\n\t\t\t\tName:  \"bif\",\n\t\t\t\tValue: true, // this value should fail validation\n\t\t\t\tValidator: func(i bool) error {\n\t\t\t\t\tif i {\n\t\t\t\t\t\treturn fmt.Errorf(\"invalid value\")\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tValidateDefaults: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\t// Default value of flag is 2 which should fail validation\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--bif\"})\n\tr.Error(err)\n}\n\nfunc TestFlagValidation(t *testing.T) {\n\tr := require.New(t)\n\n\ttestCases := []struct {\n\t\tname        string\n\t\targ         string\n\t\terrExpected bool\n\t}{\n\t\t{\n\t\t\tname:        \"first range less than min\",\n\t\t\targ:         \"2\",\n\t\t\terrExpected: true,\n\t\t},\n\t\t{\n\t\t\tname: \"first range min\",\n\t\t\targ:  \"3\",\n\t\t},\n\t\t{\n\t\t\tname: \"first range mid\",\n\t\t\targ:  \"7\",\n\t\t},\n\t\t{\n\t\t\tname: \"first range max\",\n\t\t\targ:  \"10\",\n\t\t},\n\t\t{\n\t\t\tname:        \"first range greater than max\",\n\t\t\targ:         \"15\",\n\t\t\terrExpected: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"second range less than min\",\n\t\t\targ:         \"19\",\n\t\t\terrExpected: true,\n\t\t},\n\t\t{\n\t\t\tname: \"second range min\",\n\t\t\targ:  \"20\",\n\t\t},\n\t\t{\n\t\t\tname: \"second range mid\",\n\t\t\targ:  \"21\",\n\t\t},\n\t\t{\n\t\t\tname: \"second range max\",\n\t\t\targ:  \"24\",\n\t\t},\n\t\t{\n\t\t\tname:        \"second range greater than max\",\n\t\t\targ:         \"27\",\n\t\t\terrExpected: true,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tcmd := &Command{\n\t\t\tName: \"foo\",\n\t\t\tFlags: []Flag{\n\t\t\t\t&Int64Flag{\n\t\t\t\t\tName:  \"it\",\n\t\t\t\t\tValue: 5, // note that this value should pass validation\n\t\t\t\t\tValidator: func(i int64) error {\n\t\t\t\t\t\tif (i >= 3 && i <= 10) || (i >= 20 && i <= 24) {\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn fmt.Errorf(\"Value %d not in range [3,10]U[20,24]\", i)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--it\", testCase.arg})\n\t\tif !testCase.errExpected {\n\t\t\tr.NoError(err)\n\t\t} else {\n\t\t\tr.Error(err)\n\t\t}\n\t}\n}\n\nfunc TestBoolInverseFlagValidation(t *testing.T) {\n\tr := require.New(t)\n\n\tcmd := &Command{\n\t\tName: \"foo\",\n\t\tFlags: []Flag{\n\t\t\t&BoolWithInverseFlag{\n\t\t\t\tName: \"it\",\n\t\t\t\tValidator: func(b bool) error {\n\t\t\t\t\tif b {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t\treturn fmt.Errorf(\"not valid\")\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"--it=false\"})\n\tr.Error(err)\n}\n"
  },
  {
    "path": "funcs.go",
    "content": "package cli\n\nimport \"context\"\n\n// ShellCompleteFunc is an action to execute when the shell completion flag is set\ntype ShellCompleteFunc func(context.Context, *Command)\n\n// BeforeFunc is an action that executes prior to any subcommands being run once\n// the context is ready.  If a non-nil error is returned, no subcommands are\n// run.\ntype BeforeFunc func(context.Context, *Command) (context.Context, error)\n\n// AfterFunc is an action that executes after any subcommands are run and have\n// finished. The AfterFunc is run even if Action() panics.\ntype AfterFunc func(context.Context, *Command) error\n\n// ActionFunc is the action to execute when no subcommands are specified\ntype ActionFunc func(context.Context, *Command) error\n\n// CommandNotFoundFunc is executed if the proper command cannot be found\ntype CommandNotFoundFunc func(context.Context, *Command, string)\n\n// ConfigureShellCompletionCommand is a function to configure a shell completion command\ntype ConfigureShellCompletionCommand func(*Command)\n\n// OnUsageErrorFunc is executed if a usage error occurs. This is useful for displaying\n// customized usage error messages.  This function is able to replace the\n// original error messages.  If this function is not set, the \"Incorrect usage\"\n// is displayed and the execution is interrupted.\ntype OnUsageErrorFunc func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error\n\n// InvalidFlagAccessFunc is executed when an invalid flag is accessed from the context.\ntype InvalidFlagAccessFunc func(context.Context, *Command, string)\n\n// ExitErrHandlerFunc is executed if provided in order to handle exitError values\n// returned by Actions and Before/After functions.\ntype ExitErrHandlerFunc func(context.Context, *Command, error)\n\n// FlagStringFunc is used by the help generation to display a flag, which is\n// expected to be a single line.\ntype FlagStringFunc func(Flag) string\n\n// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix\n// text for a flag's full name.\ntype FlagNamePrefixFunc func(fullName []string, placeholder string) string\n\n// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help\n// with the environment variable details.\ntype FlagEnvHintFunc func(envVars []string, str string) string\n\n// FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help\n// with the file path details.\ntype FlagFileHintFunc func(filePath, str string) string\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/urfave/cli/v3\n\ngo 1.22\n\nrequire github.com/stretchr/testify v1.11.1\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "godoc-current.txt",
    "content": "package cli // import \"github.com/urfave/cli/v3\"\n\nPackage cli provides a minimal framework for creating and organizing command\nline Go applications. cli is designed to be easy to understand and write,\nthe most simple cli application can be written as follows:\n\n    func main() {\n    \t(&cli.Command{}).Run(context.Background(), os.Args)\n    }\n\nOf course this application does not do much, so let's make this an actual\napplication:\n\n    func main() {\n    \tcmd := &cli.Command{\n      \t\tName: \"greet\",\n      \t\tUsage: \"say a greeting\",\n      \t\tAction: func(c *cli.Context) error {\n      \t\t\tfmt.Println(\"Greetings\")\n      \t\t\treturn nil\n      \t\t},\n    \t}\n\n    \tcmd.Run(context.Background(), os.Args)\n    }\n\nVARIABLES\n\nvar (\n\tNewFloatSlice   = NewSliceBase[float64, NoConfig, floatValue[float64]]\n\tNewFloat32Slice = NewSliceBase[float32, NoConfig, floatValue[float32]]\n\tNewFloat64Slice = NewSliceBase[float64, NoConfig, floatValue[float64]]\n)\nvar (\n\tNewIntSlice   = NewSliceBase[int, IntegerConfig, intValue[int]]\n\tNewInt8Slice  = NewSliceBase[int8, IntegerConfig, intValue[int8]]\n\tNewInt16Slice = NewSliceBase[int16, IntegerConfig, intValue[int16]]\n\tNewInt32Slice = NewSliceBase[int32, IntegerConfig, intValue[int32]]\n\tNewInt64Slice = NewSliceBase[int64, IntegerConfig, intValue[int64]]\n)\nvar (\n\tNewUintSlice   = NewSliceBase[uint, IntegerConfig, uintValue[uint]]\n\tNewUint8Slice  = NewSliceBase[uint8, IntegerConfig, uintValue[uint8]]\n\tNewUint16Slice = NewSliceBase[uint16, IntegerConfig, uintValue[uint16]]\n\tNewUint32Slice = NewSliceBase[uint32, IntegerConfig, uintValue[uint32]]\n\tNewUint64Slice = NewSliceBase[uint64, IntegerConfig, uintValue[uint64]]\n)\nvar (\n\tSuggestFlag               SuggestFlagFunc    = suggestFlag\n\tSuggestCommand            SuggestCommandFunc = suggestCommand\n\tSuggestDidYouMeanTemplate string             = suggestDidYouMeanTemplate\n)\nvar AnyArguments = []Argument{\n\t&StringArgs{\n\t\tMax: -1,\n\t},\n}\n    AnyArguments to differentiate between no arguments(nil) vs aleast one\n\nvar ArgsUsageCommandHelp = \"[command]\"\n    ArgsUsageCommandHelp is a short description of the arguments of the help\n    command\n\nvar CommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{template \"usageTemplate\" .}}{{if .Category}}\n\nCATEGORY:\n   {{.Category}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nOPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nOPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}{{if .VisiblePersistentFlags}}\n\nGLOBAL OPTIONS:{{template \"visiblePersistentFlagTemplate\" .}}{{end}}\n`\n    CommandHelpTemplate is the text template for the command help topic. cli.go\n    uses text/template to render templates. You can render custom help text by\n    setting this variable.\n\nvar DefaultAppComplete = DefaultRootCommandComplete\n    DefaultAppComplete is a backward-compatible name for\n    DefaultRootCommandComplete.\n\nvar DefaultInverseBoolPrefix = \"no-\"\nvar ErrWriter io.Writer = os.Stderr\n    ErrWriter is used to write errors to the user. This can be anything\n    implementing the io.Writer interface and defaults to os.Stderr.\n\nvar FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion\n\nfunction __fish_{{ .Command.Name }}_no_subcommand --description 'Test if there has been any subcommand yet'\n    for i in (commandline -opc)\n        if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }}\n            return 1\n        end\n    end\n    return 0\nend\n\n{{ range $v := .Completions }}{{ $v }}\n{{ end }}`\nvar NewStringMap = NewMapBase[string, StringConfig, stringValue]\nvar NewStringSlice = NewSliceBase[string, StringConfig, stringValue]\nvar OsExiter = os.Exit\n    OsExiter is the function used when the app exits. If not set defaults to\n    os.Exit.\n\nvar RootCommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}} {{if .VisibleFlags}}[global options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}\n\nVERSION:\n   {{.Version}}{{end}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}\n{{- if len .Authors}}\n\nAUTHOR{{template \"authorsTemplate\" .}}{{end}}{{if .VisibleCommands}}\n\nCOMMANDS:{{template \"visibleCommandCategoryTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nGLOBAL OPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nGLOBAL OPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}{{if .Copyright}}\n\nCOPYRIGHT:\n   {{template \"copyrightTemplate\" .}}{{end}}\n`\n    RootCommandHelpTemplate is the text template for the Default help topic.\n    cli.go uses text/template to render templates. You can render custom help\n    text by setting this variable.\n\nvar ShowAppHelp = ShowRootCommandHelp\n    ShowAppHelp is a backward-compatible name for ShowRootCommandHelp.\n\nvar ShowAppHelpAndExit = ShowRootCommandHelpAndExit\n    ShowAppHelpAndExit is a backward-compatible name for ShowRootCommandHelp.\n\nvar ShowCommandHelp = DefaultShowCommandHelp\n    ShowCommandHelp prints help for the given command\n\nvar ShowRootCommandHelp = DefaultShowRootCommandHelp\n    ShowRootCommandHelp is an action that displays help for the root command.\n\nvar ShowSubcommandHelp = DefaultShowSubcommandHelp\n    ShowSubcommandHelp prints help for the given subcommand\n\nvar SubcommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Category}}\n\nCATEGORY:\n   {{.Category}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}{{if .VisibleCommands}}\n\nCOMMANDS:{{template \"visibleCommandTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nOPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nOPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}\n`\n    SubcommandHelpTemplate is the text template for the subcommand help topic.\n    cli.go uses text/template to render templates. You can render custom help\n    text by setting this variable.\n\nvar UsageCommandHelp = \"Shows a list of commands or help for one command\"\n    UsageCommandHelp is the text to override the USAGE section of the help\n    command\n\nvar VersionPrinter = DefaultPrintVersion\n    VersionPrinter prints the version for the root Command.\n\n\nFUNCTIONS\n\nfunc DefaultCompleteWithFlags(ctx context.Context, cmd *Command)\nfunc DefaultPrintHelp(out io.Writer, templ string, data any)\n    DefaultPrintHelp is the default implementation of HelpPrinter.\n\nfunc DefaultPrintHelpCustom(out io.Writer, templ string, data any, customFuncs map[string]any)\n    DefaultPrintHelpCustom is the default implementation of HelpPrinterCustom.\n\n    The customFuncs map will be combined with a default template.FuncMap to\n    allow using arbitrary functions in template rendering.\n\nfunc DefaultPrintVersion(cmd *Command)\n    DefaultPrintVersion is the default implementation of VersionPrinter.\n\nfunc DefaultRootCommandComplete(ctx context.Context, cmd *Command)\n    DefaultRootCommandComplete prints the list of subcommands as the default\n    completion method.\n\nfunc DefaultShowCommandHelp(ctx context.Context, cmd *Command, commandName string) error\n    DefaultShowCommandHelp is the default implementation of ShowCommandHelp.\n\nfunc DefaultShowRootCommandHelp(cmd *Command) error\n    DefaultShowRootCommandHelp is the default implementation of\n    ShowRootCommandHelp.\n\nfunc DefaultShowSubcommandHelp(cmd *Command) error\n    DefaultShowSubcommandHelp is the default implementation of\n    ShowSubcommandHelp.\n\nfunc FlagNames(name string, aliases []string) []string\nfunc HandleExitCoder(err error)\n    HandleExitCoder handles errors implementing ExitCoder by printing their\n    message and calling OsExiter with the given exit code.\n\n    If the given error instead implements MultiError, each error will be checked\n    for the ExitCoder interface, and OsExiter will be called with the last exit\n    code found, or exit code 1 if no ExitCoder is found.\n\n    This function is the default error-handling behavior for a Command.\n\nfunc ShowCommandHelpAndExit(ctx context.Context, cmd *Command, command string, code int)\n    ShowCommandHelpAndExit exits with code after showing help via\n    ShowCommandHelp.\n\nfunc ShowRootCommandHelpAndExit(cmd *Command, exitCode int)\n    ShowRootCommandHelpAndExit prints the list of subcommands and exits with\n    exit code.\n\nfunc ShowSubcommandHelpAndExit(cmd *Command, exitCode int)\n    ShowSubcommandHelpAndExit prints help for the given subcommand via\n    ShowSubcommandHelp and exits with exit code.\n\nfunc ShowVersion(cmd *Command)\n    ShowVersion prints the version number of the root Command.\n\n\nTYPES\n\ntype ActionFunc func(context.Context, *Command) error\n    ActionFunc is the action to execute when no subcommands are specified\n\ntype ActionableFlag interface {\n\tRunAction(context.Context, *Command) error\n}\n    ActionableFlag is an interface that wraps Flag interface and RunAction\n    operation.\n\ntype AfterFunc func(context.Context, *Command) error\n    AfterFunc is an action that executes after any subcommands are run and have\n    finished. The AfterFunc is run even if Action() panics.\n\ntype Args interface {\n\t// Get returns the nth argument, or else a blank string\n\tGet(n int) string\n\t// First returns the first argument, or else a blank string\n\tFirst() string\n\t// Tail returns the rest of the arguments (not the first one)\n\t// or else an empty string slice\n\tTail() []string\n\t// Len returns the length of the wrapped slice\n\tLen() int\n\t// Present checks if there are any arguments present\n\tPresent() bool\n\t// Slice returns a copy of the internal slice\n\tSlice() []string\n}\n\ntype Argument interface {\n\t// which this argument can be accessed using the given name\n\tHasName(string) bool\n\n\t// Parse the given args and return unparsed args and/or error\n\tParse([]string) ([]string, error)\n\n\t// The usage template for this argument to use in help\n\tUsage() string\n\n\t// The Value of this Arg\n\tGet() any\n}\n    Argument captures a positional argument that can be parsed\n\ntype ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName        string `json:\"name\"`      // the name of this argument\n\tValue       T      `json:\"value\"`     // the default value of this argument\n\tDestination *T     `json:\"-\"`         // the destination point for this argument\n\tUsageText   string `json:\"usageText\"` // the usage text to show\n\tConfig      C      `json:\"config\"`    // config for this argument similar to Flag Config\n\n\t// Has unexported fields.\n}\n\nfunc (a *ArgumentBase[T, C, VC]) Get() any\n\nfunc (a *ArgumentBase[T, C, VC]) HasName(s string) bool\n\nfunc (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error)\n\nfunc (a *ArgumentBase[T, C, VC]) Usage() string\n\ntype ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName        string `json:\"name\"`      // the name of this argument\n\tValue       T      `json:\"value\"`     // the default value of this argument\n\tDestination *[]T   `json:\"-\"`         // the destination point for this argument\n\tUsageText   string `json:\"usageText\"` // the usage text to show\n\tMin         int    `json:\"minTimes\"`  // the min num of occurrences of this argument\n\tMax         int    `json:\"maxTimes\"`  // the max num of occurrences of this argument, set to -1 for unlimited\n\tConfig      C      `json:\"config\"`    // config for this argument similar to Flag Config\n\n\t// Has unexported fields.\n}\n    ArgumentsBase is a base type for slice arguments\n\nfunc (a *ArgumentsBase[T, C, VC]) Get() any\n\nfunc (a *ArgumentsBase[T, C, VC]) HasName(s string) bool\n\nfunc (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error)\n\nfunc (a *ArgumentsBase[T, C, VC]) Usage() string\n\ntype BeforeFunc func(context.Context, *Command) (context.Context, error)\n    BeforeFunc is an action that executes prior to any subcommands being run\n    once the context is ready. If a non-nil error is returned, no subcommands\n    are run.\n\ntype BoolConfig struct {\n\tCount *int\n}\n    BoolConfig defines the configuration for bool flags\n\ntype BoolFlag = FlagBase[bool, BoolConfig, boolValue]\n\ntype BoolWithInverseFlag struct {\n\tName             string                                      `json:\"name\"`             // name of the flag\n\tCategory         string                                      `json:\"category\"`         // category of the flag, if any\n\tDefaultText      string                                      `json:\"defaultText\"`      // default text of the flag for usage purposes\n\tHideDefault      bool                                        `json:\"hideDefault\"`      // whether to hide the default value in output\n\tUsage            string                                      `json:\"usage\"`            // usage string for help output\n\tSources          ValueSourceChain                            `json:\"-\"`                // sources to load flag value from\n\tRequired         bool                                        `json:\"required\"`         // whether the flag is required or not\n\tHidden           bool                                        `json:\"hidden\"`           // whether to hide the flag in help output\n\tLocal            bool                                        `json:\"local\"`            // whether the flag needs to be applied to subcommands as well\n\tValue            bool                                        `json:\"defaultValue\"`     // default value for this flag if not set by from any source\n\tDestination      *bool                                       `json:\"-\"`                // destination pointer for value when set\n\tAliases          []string                                    `json:\"aliases\"`          // Aliases that are allowed for this flag\n\tTakesFile        bool                                        `json:\"takesFileArg\"`     // whether this flag takes a file argument, mainly for shell completion purposes\n\tAction           func(context.Context, *Command, bool) error `json:\"-\"`                // Action callback to be called when flag is set\n\tOnlyOnce         bool                                        `json:\"onlyOnce\"`         // whether this flag can be duplicated on the command line\n\tValidator        func(bool) error                            `json:\"-\"`                // custom function to validate this flag value\n\tValidateDefaults bool                                        `json:\"validateDefaults\"` // whether to validate defaults or not\n\tConfig           BoolConfig                                  `json:\"config\"`           // Additional/Custom configuration associated with this flag type\n\tInversePrefix    string                                      `json:\"invPrefix\"`        // The prefix used to indicate a negative value. Default: `env` becomes `no-env`\n\n\t// Has unexported fields.\n}\n\nfunc (bif *BoolWithInverseFlag) Count() int\n    Count returns the number of times this flag has been invoked\n\nfunc (bif *BoolWithInverseFlag) Get() any\n\nfunc (bif *BoolWithInverseFlag) GetCategory() string\n    GetCategory returns the category of the flag\n\nfunc (bif *BoolWithInverseFlag) GetDefaultText() string\n    GetDefaultText returns the default text for this flag\n\nfunc (bif *BoolWithInverseFlag) GetEnvVars() []string\n    GetEnvVars returns the env vars for this flag\n\nfunc (bif *BoolWithInverseFlag) GetUsage() string\n    GetUsage returns the usage string for the flag\n\nfunc (bif *BoolWithInverseFlag) GetValue() string\n    GetValue returns the flags value as string representation and an empty\n    string if the flag takes no value at all.\n\nfunc (bif *BoolWithInverseFlag) IsBoolFlag() bool\n    IsBoolFlag returns whether the flag doesnt need to accept args\n\nfunc (bif *BoolWithInverseFlag) IsDefaultVisible() bool\n    IsDefaultVisible returns true if the flag is not hidden, otherwise false\n\nfunc (bif *BoolWithInverseFlag) IsLocal() bool\n\nfunc (bif *BoolWithInverseFlag) IsRequired() bool\n\nfunc (bif *BoolWithInverseFlag) IsSet() bool\n\nfunc (bif *BoolWithInverseFlag) IsVisible() bool\n\nfunc (bif *BoolWithInverseFlag) Names() []string\n\nfunc (bif *BoolWithInverseFlag) PostParse() error\n\nfunc (bif *BoolWithInverseFlag) PreParse() error\n\nfunc (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error\n\nfunc (bif *BoolWithInverseFlag) Set(name, val string) error\n\nfunc (bif *BoolWithInverseFlag) SetCategory(c string)\n\nfunc (bif *BoolWithInverseFlag) String() string\n    String implements the standard Stringer interface.\n\n    Example for BoolFlag{Name: \"env\"} --[no-]env (default: false)\n\nfunc (bif *BoolWithInverseFlag) TakesValue() bool\n\nfunc (bif *BoolWithInverseFlag) TypeName() string\n    TypeName is used for stringify/docs. For bool its a no-op\n\ntype CategorizableFlag interface {\n\t// Returns the category of the flag\n\tGetCategory() string\n\n\t// Sets the category of the flag\n\tSetCategory(string)\n}\n    CategorizableFlag is an interface that allows us to potentially use a flag\n    in a categorized representation.\n\ntype Command struct {\n\t// The name of the command\n\tName string `json:\"name\"`\n\t// A list of aliases for the command\n\tAliases []string `json:\"aliases\"`\n\t// A short description of the usage of this command\n\tUsage string `json:\"usage\"`\n\t// Text to override the USAGE section of help\n\tUsageText string `json:\"usageText\"`\n\t// A short description of the arguments of this command\n\tArgsUsage string `json:\"argsUsage\"`\n\t// Version of the command\n\tVersion string `json:\"version\"`\n\t// Longer explanation of how the command works\n\tDescription string `json:\"description\"`\n\t// DefaultCommand is the (optional) name of a command\n\t// to run if no command names are passed as CLI arguments.\n\tDefaultCommand string `json:\"defaultCommand\"`\n\t// The category the command is part of\n\tCategory string `json:\"category\"`\n\t// List of child commands\n\tCommands []*Command `json:\"commands\"`\n\t// List of flags to parse\n\tFlags []Flag `json:\"flags\"`\n\t// Boolean to hide built-in help command and help flag\n\tHideHelp bool `json:\"hideHelp\"`\n\t// Ignored if HideHelp is true.\n\tHideHelpCommand bool `json:\"hideHelpCommand\"`\n\t// Boolean to hide built-in version flag and the VERSION section of help\n\tHideVersion bool `json:\"hideVersion\"`\n\t// Boolean to enable shell completion commands\n\tEnableShellCompletion bool `json:\"-\"`\n\t// Shell Completion generation command name\n\tShellCompletionCommandName string `json:\"-\"`\n\t// The function to call when checking for shell command completions\n\tShellComplete ShellCompleteFunc `json:\"-\"`\n\t// The function to configure a shell completion command\n\tConfigureShellCompletionCommand ConfigureShellCompletionCommand `json:\"-\"`\n\t// An action to execute before any subcommands are run, but after the context is ready\n\t// If a non-nil error is returned, no subcommands are run\n\tBefore BeforeFunc `json:\"-\"`\n\t// An action to execute after any subcommands are run, but after the subcommand has finished\n\t// It is run even if Action() panics\n\tAfter AfterFunc `json:\"-\"`\n\t// The function to call when this command is invoked\n\tAction ActionFunc `json:\"-\"`\n\t// Execute this function if the proper command cannot be found\n\tCommandNotFound CommandNotFoundFunc `json:\"-\"`\n\t// Execute this function if a usage error occurs.\n\tOnUsageError OnUsageErrorFunc `json:\"-\"`\n\t// Execute this function when an invalid flag is accessed from the context\n\tInvalidFlagAccessHandler InvalidFlagAccessFunc `json:\"-\"`\n\t// Boolean to hide this command from help or completion\n\tHidden bool `json:\"hidden\"`\n\t// List of all authors who contributed (string or fmt.Stringer)\n\t// TODO: ~string | fmt.Stringer when interface unions are available\n\tAuthors []any `json:\"authors\"`\n\t// Copyright of the binary if any\n\tCopyright string `json:\"copyright\"`\n\t// Reader reader to write input to (useful for tests)\n\tReader io.Reader `json:\"-\"`\n\t// Writer writer to write output to\n\tWriter io.Writer `json:\"-\"`\n\t// ErrWriter writes error output\n\tErrWriter io.Writer `json:\"-\"`\n\t// ExitErrHandler processes any error encountered while running a Command before it is\n\t// returned to the caller. If no function is provided, HandleExitCoder is used as the\n\t// default behavior.\n\tExitErrHandler ExitErrHandlerFunc `json:\"-\"`\n\t// Other custom info\n\tMetadata map[string]interface{} `json:\"metadata\"`\n\t// Carries a function which returns app specific info.\n\tExtraInfo func() map[string]string `json:\"-\"`\n\t// CustomRootCommandHelpTemplate the text template for app help topic.\n\t// cli.go uses text/template to render templates. You can\n\t// render custom help text by setting this variable.\n\tCustomRootCommandHelpTemplate string `json:\"-\"`\n\t// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is \",\"\n\tSliceFlagSeparator string `json:\"sliceFlagSeparator\"`\n\t// DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false\n\tDisableSliceFlagSeparator bool `json:\"disableSliceFlagSeparator\"`\n\t// MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is \"=\"\n\tMapFlagKeyValueSeparator string `json:\"mapFlagKeyValueSeparator\"`\n\t// Boolean to enable short-option handling so user can combine several\n\t// single-character bool arguments into one\n\t// i.e. foobar -o -v -> foobar -ov\n\tUseShortOptionHandling bool `json:\"useShortOptionHandling\"`\n\t// Enable suggestions for commands and flags\n\tSuggest bool `json:\"suggest\"`\n\t// Allows global flags set by libraries which use flag.XXXVar(...) directly\n\t// to be parsed through this library\n\tAllowExtFlags bool `json:\"allowExtFlags\"`\n\t// Treat all flags as normal arguments if true\n\tSkipFlagParsing bool `json:\"skipFlagParsing\"`\n\t// CustomHelpTemplate the text template for the command help topic.\n\t// cli.go uses text/template to render templates. You can\n\t// render custom help text by setting this variable.\n\tCustomHelpTemplate string `json:\"-\"`\n\t// Use longest prefix match for commands\n\tPrefixMatchCommands bool `json:\"prefixMatchCommands\"`\n\t// Custom suggest command for matching\n\tSuggestCommandFunc SuggestCommandFunc `json:\"-\"`\n\t// Flag exclusion group\n\tMutuallyExclusiveFlags []MutuallyExclusiveFlags `json:\"mutuallyExclusiveFlags\"`\n\t// Arguments to parse for this command\n\tArguments []Argument `json:\"arguments\"`\n\t// Whether to read arguments from stdin\n\t// applicable to root command only\n\tReadArgsFromStdin bool `json:\"readArgsFromStdin\"`\n\t// StopOnNthArg provides v2-like behavior for specific commands by stopping\n\t// flag parsing after N positional arguments are encountered. When set to N,\n\t// all remaining arguments after the Nth positional argument will be treated\n\t// as arguments, not flags.\n\t//\n\t// A value of 0 means all arguments are treated as positional (no flag parsing).\n\t// A nil value means normal v3 flag parsing behavior (flags can appear anywhere).\n\tStopOnNthArg *int `json:\"stopOnNthArg\"`\n\n\t// Has unexported fields.\n}\n    Command contains everything needed to run an application that accepts a\n    string slice of arguments such as os.Args. A given Command may contain Flags\n    and sub-commands in Commands.\n\nfunc (cmd *Command) Args() Args\n    Args returns the command line arguments associated with the command.\n\nfunc (cmd *Command) Bool(name string) bool\n\nfunc (cmd *Command) Command(name string) *Command\n\nfunc (cmd *Command) Count(name string) int\n    Count returns the num of occurrences of this flag\n\nfunc (cmd *Command) Duration(name string) time.Duration\n\nfunc (cmd *Command) FlagNames() []string\n    FlagNames returns a slice of flag names used by the this command and all of\n    its parent commands.\n\nfunc (cmd *Command) Float(name string) float64\n    Float looks up the value of a local FloatFlag, returns 0 if not found\n\nfunc (cmd *Command) Float32(name string) float32\n    Float32 looks up the value of a local Float32Flag, returns 0 if not found\n\nfunc (c *Command) Float32Arg(name string) float32\n\nfunc (c *Command) Float32Args(name string) []float32\n\nfunc (cmd *Command) Float32Slice(name string) []float32\n    Float32Slice looks up the value of a local Float32Slice, returns nil if not\n    found\n\nfunc (cmd *Command) Float64(name string) float64\n    Float64 looks up the value of a local Float64Flag, returns 0 if not found\n\nfunc (c *Command) Float64Arg(name string) float64\n\nfunc (c *Command) Float64Args(name string) []float64\n\nfunc (cmd *Command) Float64Slice(name string) []float64\n    Float64Slice looks up the value of a local Float64SliceFlag, returns nil if\n    not found\n\nfunc (c *Command) FloatArg(name string) float64\n\nfunc (c *Command) FloatArgs(name string) []float64\n\nfunc (cmd *Command) FloatSlice(name string) []float64\n    FloatSlice looks up the value of a local FloatSliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) FullName() string\n    FullName returns the full name of the command. For commands with parents\n    this ensures that the parent commands are part of the command path.\n\nfunc (cmd *Command) Generic(name string) Value\n    Generic looks up the value of a local GenericFlag, returns nil if not found\n\nfunc (cmd *Command) HasName(name string) bool\n    HasName returns true if Command.Name matches given name\n\nfunc (cmd *Command) Int(name string) int\n    Int looks up the value of a local Int64Flag, returns 0 if not found\n\nfunc (cmd *Command) Int16(name string) int16\n    Int16 looks up the value of a local Int16Flag, returns 0 if not found\n\nfunc (c *Command) Int16Arg(name string) int16\n\nfunc (c *Command) Int16Args(name string) []int16\n\nfunc (cmd *Command) Int16Slice(name string) []int16\n    Int16Slice looks up the value of a local Int16SliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Int32(name string) int32\n    Int32 looks up the value of a local Int32Flag, returns 0 if not found\n\nfunc (c *Command) Int32Arg(name string) int32\n\nfunc (c *Command) Int32Args(name string) []int32\n\nfunc (cmd *Command) Int32Slice(name string) []int32\n    Int32Slice looks up the value of a local Int32SliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Int64(name string) int64\n    Int64 looks up the value of a local Int64Flag, returns 0 if not found\n\nfunc (c *Command) Int64Arg(name string) int64\n\nfunc (c *Command) Int64Args(name string) []int64\n\nfunc (cmd *Command) Int64Slice(name string) []int64\n    Int64Slice looks up the value of a local Int64SliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Int8(name string) int8\n    Int8 looks up the value of a local Int8Flag, returns 0 if not found\n\nfunc (c *Command) Int8Arg(name string) int8\n\nfunc (c *Command) Int8Args(name string) []int8\n\nfunc (cmd *Command) Int8Slice(name string) []int8\n    Int8Slice looks up the value of a local Int8SliceFlag, returns nil if not\n    found\n\nfunc (c *Command) IntArg(name string) int\n\nfunc (c *Command) IntArgs(name string) []int\n\nfunc (cmd *Command) IntSlice(name string) []int\n    IntSlice looks up the value of a local IntSliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) IsSet(name string) bool\n    IsSet determines if the flag was actually set\n\nfunc (cmd *Command) Lineage() []*Command\n    Lineage returns *this* command and all of its ancestor commands in order\n    from child to parent\n\nfunc (cmd *Command) LocalFlagNames() []string\n    LocalFlagNames returns a slice of flag names used in this command.\n\nfunc (cmd *Command) NArg() int\n    NArg returns the number of the command line arguments.\n\nfunc (cmd *Command) Names() []string\n    Names returns the names including short names and aliases.\n\nfunc (cmd *Command) NumFlags() int\n    NumFlags returns the number of flags set\n\nfunc (cmd *Command) Root() *Command\n    Root returns the Command at the root of the graph\n\nfunc (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error)\n    Run is the entry point to the command graph. The positional arguments are\n    parsed according to the Flag and Command definitions and the matching Action\n    functions are run.\n\nfunc (cmd *Command) Set(name, value string) error\n    Set sets a context flag to a value.\n\nfunc (cmd *Command) String(name string) string\n\nfunc (c *Command) StringArg(name string) string\n\nfunc (c *Command) StringArgs(name string) []string\n\nfunc (cmd *Command) StringMap(name string) map[string]string\n    StringMap looks up the value of a local StringMapFlag, returns nil if not\n    found\n\nfunc (cmd *Command) StringSlice(name string) []string\n    StringSlice looks up the value of a local StringSliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Timestamp(name string) time.Time\n    Timestamp gets the timestamp from a flag name\n\nfunc (c *Command) TimestampArg(name string) time.Time\n\nfunc (c *Command) TimestampArgs(name string) []time.Time\n\nfunc (cmd *Command) ToFishCompletion() (string, error)\n    ToFishCompletion creates a fish completion string for the `*Command` The\n    function errors if either parsing or writing of the string fails.\n\nfunc (cmd *Command) Uint(name string) uint\n    Uint looks up the value of a local Uint64Flag, returns 0 if not found\n\nfunc (cmd *Command) Uint16(name string) uint16\n    Uint16 looks up the value of a local Uint16Flag, returns 0 if not found\n\nfunc (c *Command) Uint16Arg(name string) uint16\n\nfunc (c *Command) Uint16Args(name string) []uint16\n\nfunc (cmd *Command) Uint16Slice(name string) []uint16\n    Uint16Slice looks up the value of a local Uint16SliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Uint32(name string) uint32\n    Uint32 looks up the value of a local Uint32Flag, returns 0 if not found\n\nfunc (c *Command) Uint32Arg(name string) uint32\n\nfunc (c *Command) Uint32Args(name string) []uint32\n\nfunc (cmd *Command) Uint32Slice(name string) []uint32\n    Uint32Slice looks up the value of a local Uint32SliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Uint64(name string) uint64\n    Uint64 looks up the value of a local Uint64Flag, returns 0 if not found\n\nfunc (c *Command) Uint64Arg(name string) uint64\n\nfunc (c *Command) Uint64Args(name string) []uint64\n\nfunc (cmd *Command) Uint64Slice(name string) []uint64\n    Uint64Slice looks up the value of a local Uint64SliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Uint8(name string) uint8\n    Uint8 looks up the value of a local Uint8Flag, returns 0 if not found\n\nfunc (c *Command) Uint8Arg(name string) uint8\n\nfunc (c *Command) Uint8Args(name string) []uint8\n\nfunc (cmd *Command) Uint8Slice(name string) []uint8\n    Uint8Slice looks up the value of a local Uint8SliceFlag, returns nil if not\n    found\n\nfunc (c *Command) UintArg(name string) uint\n\nfunc (c *Command) UintArgs(name string) []uint\n\nfunc (cmd *Command) UintSlice(name string) []uint\n    UintSlice looks up the value of a local UintSliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Value(name string) interface{}\n    Value returns the value of the flag corresponding to `name`\n\nfunc (cmd *Command) VisibleCategories() []CommandCategory\n    VisibleCategories returns a slice of categories and commands that are\n    Hidden=false\n\nfunc (cmd *Command) VisibleCommands() []*Command\n    VisibleCommands returns a slice of the Commands with Hidden=false\n\nfunc (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory\n    VisibleFlagCategories returns a slice containing all the visible flag\n    categories with the flags they contain\n\nfunc (cmd *Command) VisibleFlags() []Flag\n    VisibleFlags returns a slice of the Flags with Hidden=false\n\nfunc (cmd *Command) VisiblePersistentFlags() []Flag\n    VisiblePersistentFlags returns a slice of LocalFlag with Persistent=true and\n    Hidden=false.\n\ntype CommandCategories interface {\n\t// AddCommand adds a command to a category, creating a new category if necessary.\n\tAddCommand(category string, command *Command)\n\t// Categories returns a slice of categories sorted by name\n\tCategories() []CommandCategory\n}\n    CommandCategories interface allows for category manipulation\n\ntype CommandCategory interface {\n\t// Name returns the category name string\n\tName() string\n\t// VisibleCommands returns a slice of the Commands with Hidden=false\n\tVisibleCommands() []*Command\n}\n    CommandCategory is a category containing commands.\n\ntype CommandNotFoundFunc func(context.Context, *Command, string)\n    CommandNotFoundFunc is executed if the proper command cannot be found\n\ntype ConfigureShellCompletionCommand func(*Command)\n    ConfigureShellCompletionCommand is a function to configure a shell\n    completion command\n\ntype Countable interface {\n\tCount() int\n}\n    Countable is an interface to enable detection of flag values which support\n    repetitive flags\n\ntype DocGenerationFlag interface {\n\t// TakesValue returns true if the flag takes a value, otherwise false\n\tTakesValue() bool\n\n\t// GetUsage returns the usage string for the flag\n\tGetUsage() string\n\n\t// GetValue returns the flags value as string representation and an empty\n\t// string if the flag takes no value at all.\n\tGetValue() string\n\n\t// GetDefaultText returns the default text for this flag\n\tGetDefaultText() string\n\n\t// GetEnvVars returns the env vars for this flag\n\tGetEnvVars() []string\n\n\t// IsDefaultVisible returns whether the default value should be shown in\n\t// help text\n\tIsDefaultVisible() bool\n\t// TypeName to detect if a flag is a string, bool, etc.\n\tTypeName() string\n}\n    DocGenerationFlag is an interface that allows documentation generation for\n    the flag\n\ntype DocGenerationMultiValueFlag interface {\n\tDocGenerationFlag\n\n\t// IsMultiValueFlag returns true for flags that can be given multiple times.\n\tIsMultiValueFlag() bool\n}\n    DocGenerationMultiValueFlag extends DocGenerationFlag for slice/map based\n    flags.\n\ntype DurationFlag = FlagBase[time.Duration, NoConfig, durationValue]\n\ntype EnvValueSource interface {\n\tIsFromEnv() bool\n\tKey() string\n}\n    EnvValueSource is to specifically detect env sources when printing help text\n\ntype ErrorFormatter interface {\n\tFormat(s fmt.State, verb rune)\n}\n    ErrorFormatter is the interface that will suitably format the error output\n\ntype ExitCoder interface {\n\terror\n\tExitCode() int\n}\n    ExitCoder is the interface checked by `Command` for a custom exit code.\n\nfunc Exit(message any, exitCode int) ExitCoder\n    Exit wraps a message and exit code into an error, which by default is\n    handled with a call to os.Exit during default error handling.\n\n    This is the simplest way to trigger a non-zero exit code for a Command\n    without having to call os.Exit manually. During testing, this behavior can\n    be avoided by overriding the ExitErrHandler function on a Command or the\n    package-global OsExiter function.\n\ntype ExitErrHandlerFunc func(context.Context, *Command, error)\n    ExitErrHandlerFunc is executed if provided in order to handle exitError\n    values returned by Actions and Before/After functions.\n\ntype Flag interface {\n\tfmt.Stringer\n\n\t// Retrieve the value of the Flag\n\tGet() any\n\n\t// Lifecycle methods.\n\t// flag callback prior to parsing\n\tPreParse() error\n\n\t// flag callback post parsing\n\tPostParse() error\n\n\t// Apply Flag settings to the given flag set\n\tSet(string, string) error\n\n\t// All possible names for this flag\n\tNames() []string\n\n\t// Whether the flag has been set or not\n\tIsSet() bool\n}\n    Flag is a common interface related to parsing flags in cli. For more\n    advanced flag parsing techniques, it is recommended that this interface be\n    implemented.\n\nvar GenerateShellCompletionFlag Flag = &BoolFlag{\n\tName:   \"generate-shell-completion\",\n\tHidden: true,\n}\n    GenerateShellCompletionFlag enables shell completion\n\nvar HelpFlag Flag = &BoolFlag{\n\tName:        \"help\",\n\tAliases:     []string{\"h\"},\n\tUsage:       \"show help\",\n\tHideDefault: true,\n\tLocal:       true,\n}\n    HelpFlag prints the help for all commands and subcommands. Set to nil to\n    disable the flag. The subcommand will still be added unless HideHelp or\n    HideHelpCommand is set to true.\n\nvar VersionFlag Flag = &BoolFlag{\n\tName:        \"version\",\n\tAliases:     []string{\"v\"},\n\tUsage:       \"print the version\",\n\tHideDefault: true,\n\tLocal:       true,\n}\n    VersionFlag prints the version for the application\n\ntype FlagBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName             string                                   `json:\"name\"`             // name of the flag\n\tCategory         string                                   `json:\"category\"`         // category of the flag, if any\n\tDefaultText      string                                   `json:\"defaultText\"`      // default text of the flag for usage purposes\n\tHideDefault      bool                                     `json:\"hideDefault\"`      // whether to hide the default value in output\n\tUsage            string                                   `json:\"usage\"`            // usage string for help output\n\tSources          ValueSourceChain                         `json:\"-\"`                // sources to load flag value from\n\tRequired         bool                                     `json:\"required\"`         // whether the flag is required or not\n\tHidden           bool                                     `json:\"hidden\"`           // whether to hide the flag in help output\n\tLocal            bool                                     `json:\"local\"`            // whether the flag needs to be applied to subcommands as well\n\tValue            T                                        `json:\"defaultValue\"`     // default value for this flag if not set by from any source\n\tDestination      *T                                       `json:\"-\"`                // destination pointer for value when set\n\tAliases          []string                                 `json:\"aliases\"`          // Aliases that are allowed for this flag\n\tTakesFile        bool                                     `json:\"takesFileArg\"`     // whether this flag takes a file argument, mainly for shell completion purposes\n\tAction           func(context.Context, *Command, T) error `json:\"-\"`                // Action callback to be called when flag is set\n\tConfig           C                                        `json:\"config\"`           // Additional/Custom configuration associated with this flag type\n\tOnlyOnce         bool                                     `json:\"onlyOnce\"`         // whether this flag can be duplicated on the command line\n\tValidator        func(T) error                            `json:\"-\"`                // custom function to validate this flag value\n\tValidateDefaults bool                                     `json:\"validateDefaults\"` // whether to validate defaults or not\n\n\t// Has unexported fields.\n}\n    FlagBase [T,C,VC] is a generic flag base which can be used as a boilerplate\n    to implement the most common interfaces used by urfave/cli.\n\n        T specifies the type\n        C specifies the configuration required(if any for that flag type)\n        VC specifies the value creator which creates the flag.Value emulation\n\nfunc (f *FlagBase[T, C, VC]) Count() int\n    Count returns the number of times this flag has been invoked\n\nfunc (f *FlagBase[T, C, V]) Get() any\n\nfunc (f *FlagBase[T, C, V]) GetCategory() string\n    GetCategory returns the category of the flag\n\nfunc (f *FlagBase[T, C, V]) GetDefaultText() string\n    GetDefaultText returns the default text for this flag\n\nfunc (f *FlagBase[T, C, V]) GetEnvVars() []string\n    GetEnvVars returns the env vars for this flag\n\nfunc (f *FlagBase[T, C, V]) GetUsage() string\n    GetUsage returns the usage string for the flag\n\nfunc (f *FlagBase[T, C, V]) GetValue() string\n    GetValue returns the flags value as string representation and an empty\n    string if the flag takes no value at all.\n\nfunc (f *FlagBase[T, C, VC]) IsBoolFlag() bool\n    IsBoolFlag returns whether the flag doesnt need to accept args\n\nfunc (f *FlagBase[T, C, V]) IsDefaultVisible() bool\n    IsDefaultVisible returns true if the flag is not hidden, otherwise false\n\nfunc (f *FlagBase[T, C, VC]) IsLocal() bool\n    IsLocal returns false if flag needs to be persistent across subcommands\n\nfunc (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool\n    IsMultiValueFlag returns true if the value type T can take multiple values\n    from cmd line. This is true for slice and map type flags\n\nfunc (f *FlagBase[T, C, V]) IsRequired() bool\n    IsRequired returns whether or not the flag is required\n\nfunc (f *FlagBase[T, C, V]) IsSet() bool\n    IsSet returns whether or not the flag has been set through env or file\n\nfunc (f *FlagBase[T, C, V]) IsVisible() bool\n    IsVisible returns true if the flag is not hidden, otherwise false\n\nfunc (f *FlagBase[T, C, V]) Names() []string\n    Names returns the names of the flag\n\nfunc (f *FlagBase[T, C, V]) PostParse() error\n    PostParse populates the flag given the flag set and environment\n\nfunc (f *FlagBase[T, C, V]) PreParse() error\n\nfunc (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error\n    RunAction executes flag action if set\n\nfunc (f *FlagBase[T, C, V]) Set(_ string, val string) error\n    Set applies given value from string\n\nfunc (f *FlagBase[T, C, V]) SetCategory(c string)\n\nfunc (f *FlagBase[T, C, V]) String() string\n    String returns a readable representation of this value (for usage defaults)\n\nfunc (f *FlagBase[T, C, V]) TakesValue() bool\n    TakesValue returns true if the flag takes a value, otherwise false\n\nfunc (f *FlagBase[T, C, V]) TypeName() string\n    TypeName returns the type of the flag.\n\ntype FlagCategories interface {\n\t// AddFlags adds a flag to a category, creating a new category if necessary.\n\tAddFlag(category string, fl Flag)\n\t// VisibleCategories returns a slice of visible flag categories sorted by name\n\tVisibleCategories() []VisibleFlagCategory\n}\n    FlagCategories interface allows for category manipulation\n\ntype FlagEnvHintFunc func(envVars []string, str string) string\n    FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help\n    with the environment variable details.\n\nvar FlagEnvHinter FlagEnvHintFunc = withEnvHint\n    FlagEnvHinter annotates flag help message with the environment variable\n    details. This is used by the default FlagStringer.\n\ntype FlagFileHintFunc func(filePath, str string) string\n    FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help\n    with the file path details.\n\nvar FlagFileHinter FlagFileHintFunc = withFileHint\n    FlagFileHinter annotates flag help message with the environment variable\n    details. This is used by the default FlagStringer.\n\ntype FlagNamePrefixFunc func(fullName []string, placeholder string) string\n    FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix\n    text for a flag's full name.\n\nvar FlagNamePrefixer FlagNamePrefixFunc = prefixedNames\n    FlagNamePrefixer converts a full flag name and its placeholder into the help\n    message flag prefix. This is used by the default FlagStringer.\n\ntype FlagStringFunc func(Flag) string\n    FlagStringFunc is used by the help generation to display a flag, which is\n    expected to be a single line.\n\nvar FlagStringer FlagStringFunc = stringifyFlag\n    FlagStringer converts a flag definition to a string. This is used by help to\n    display a flag.\n\ntype FlagsByName []Flag\n    FlagsByName is a slice of Flag.\n\nfunc (f FlagsByName) Len() int\n\nfunc (f FlagsByName) Less(i, j int) bool\n\nfunc (f FlagsByName) Swap(i, j int)\n\ntype Float32Arg = ArgumentBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32Args = ArgumentsBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32Flag = FlagBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32Slice = SliceBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32SliceFlag = FlagBase[[]float32, NoConfig, Float32Slice]\n\ntype Float64Arg = ArgumentBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64Args = ArgumentsBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64Flag = FlagBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64Slice = SliceBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64SliceFlag = FlagBase[[]float64, NoConfig, Float64Slice]\n\ntype FloatArg = ArgumentBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatArgs = ArgumentsBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatFlag = FlagBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatSlice = SliceBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatSliceFlag = FlagBase[[]float64, NoConfig, FloatSlice]\n\ntype GenericFlag = FlagBase[Value, NoConfig, genericValue]\n\ntype HelpPrinterCustomFunc func(w io.Writer, templ string, data any, customFunc map[string]any)\n    Prints help for the Command with custom template function.\n\nvar HelpPrinterCustom HelpPrinterCustomFunc = DefaultPrintHelpCustom\n    HelpPrinterCustom is a function that writes the help output. It is used as\n    the default implementation of HelpPrinter, and may be called directly if the\n    ExtraInfo field is set on a Command.\n\n    In the default implementation, if the customFuncs argument contains a\n    \"wrapAt\" key, which is a function which takes no arguments and returns an\n    int, this int value will be used to produce a \"wrap\" function used by the\n    default template to wrap long lines.\n\ntype HelpPrinterFunc func(w io.Writer, templ string, data any)\n    HelpPrinterFunc prints help for the Command.\n\nvar HelpPrinter HelpPrinterFunc = DefaultPrintHelp\n    HelpPrinter is a function that writes the help output. If not set\n    explicitly, this calls HelpPrinterCustom using only the default template\n    functions.\n\n    If custom logic for printing help is required, this function can be\n    overridden. If the ExtraInfo field is defined on a Command, this function\n    should not be modified, as HelpPrinterCustom will be used directly in order\n    to capture the extra information.\n\ntype Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16Args = ArgumentsBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16Flag = FlagBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16Slice = SliceBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16SliceFlag = FlagBase[[]int16, IntegerConfig, Int16Slice]\n\ntype Int32Arg = ArgumentBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32Args = ArgumentsBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32Flag = FlagBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32Slice = SliceBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32SliceFlag = FlagBase[[]int32, IntegerConfig, Int32Slice]\n\ntype Int64Arg = ArgumentBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64Args = ArgumentsBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64Flag = FlagBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64Slice = SliceBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64SliceFlag = FlagBase[[]int64, IntegerConfig, Int64Slice]\n\ntype Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8Args = ArgumentsBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8Flag = FlagBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8Slice = SliceBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8SliceFlag = FlagBase[[]int8, IntegerConfig, Int8Slice]\n\ntype IntArg = ArgumentBase[int, IntegerConfig, intValue[int]]\n\ntype IntArgs = ArgumentsBase[int, IntegerConfig, intValue[int]]\n\ntype IntFlag = FlagBase[int, IntegerConfig, intValue[int]]\n\ntype IntSlice = SliceBase[int, IntegerConfig, intValue[int]]\n\ntype IntSliceFlag = FlagBase[[]int, IntegerConfig, IntSlice]\n\ntype IntegerConfig struct {\n\tBase int\n}\n    IntegerConfig is the configuration for all integer type flags\n\ntype InvalidFlagAccessFunc func(context.Context, *Command, string)\n    InvalidFlagAccessFunc is executed when an invalid flag is accessed from the\n    context.\n\ntype LocalFlag interface {\n\tIsLocal() bool\n}\n    LocalFlag is an interface to enable detection of flags which are local to\n    current command\n\ntype MapBase[T any, C any, VC ValueCreator[T, C]] struct {\n\t// Has unexported fields.\n}\n    MapBase wraps map[string]T to satisfy flag.Value\n\nfunc NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string]T) *MapBase[T, C, VC]\n    NewMapBase makes a *MapBase with default values\n\nfunc (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value\n\nfunc (i *MapBase[T, C, VC]) Get() interface{}\n    Get returns the mapping of values set by this flag\n\nfunc (i *MapBase[T, C, VC]) Serialize() string\n    Serialize allows MapBase to fulfill Serializer\n\nfunc (i *MapBase[T, C, VC]) Set(value string) error\n    Set parses the value and appends it to the list of values\n\nfunc (i *MapBase[T, C, VC]) String() string\n    String returns a readable representation of this value (for usage defaults)\n\nfunc (i MapBase[T, C, VC]) ToString(t map[string]T) string\n\nfunc (i *MapBase[T, C, VC]) Value() map[string]T\n    Value returns the mapping of values set by this flag\n\ntype MapSource interface {\n\tfmt.Stringer\n\tfmt.GoStringer\n\n\t// Lookup returns the value from the source based on key\n\t// and if it was found\n\t// or returns an empty string and false\n\tLookup(string) (any, bool)\n}\n    MapSource is a source which can be used to look up a value based on a key\n    typically for use with a cli.Flag\n\nfunc NewMapSource(name string, m map[any]any) MapSource\n\ntype MultiError interface {\n\terror\n\tErrors() []error\n}\n    MultiError is an error that wraps multiple errors.\n\ntype MutuallyExclusiveFlags struct {\n\t// Flag list\n\tFlags [][]Flag\n\n\t// whether this group is required\n\tRequired bool\n\n\t// Category to apply to all flags within group\n\tCategory string\n}\n    MutuallyExclusiveFlags defines a mutually exclusive flag group Multiple\n    option paths can be provided out of which only one can be defined on cmdline\n    So for example [ --foo | [ --bar something --darth somethingelse ] ]\n\ntype NoConfig struct{}\n    NoConfig is for flags which dont need a custom configuration\n\ntype OnUsageErrorFunc func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error\n    OnUsageErrorFunc is executed if a usage error occurs. This is useful for\n    displaying customized usage error messages. This function is able to replace\n    the original error messages. If this function is not set, the \"Incorrect\n    usage\" is displayed and the execution is interrupted.\n\ntype RequiredFlag interface {\n\t// whether the flag is a required flag or not\n\tIsRequired() bool\n}\n    RequiredFlag is an interface that allows us to mark flags as required\n    it allows flags required flags to be backwards compatible with the Flag\n    interface\n\ntype Serializer interface {\n\tSerialize() string\n}\n    Serializer is used to circumvent the limitations of flag.FlagSet.Set\n\ntype ShellCompleteFunc func(context.Context, *Command)\n    ShellCompleteFunc is an action to execute when the shell completion flag is\n    set\n\ntype SliceBase[T any, C any, VC ValueCreator[T, C]] struct {\n\t// Has unexported fields.\n}\n    SliceBase wraps []T to satisfy flag.Value\n\nfunc NewSliceBase[T any, C any, VC ValueCreator[T, C]](defaults ...T) *SliceBase[T, C, VC]\n    NewSliceBase makes a *SliceBase with default values\n\nfunc (i SliceBase[T, C, VC]) Create(val []T, p *[]T, c C) Value\n\nfunc (i *SliceBase[T, C, VC]) Get() interface{}\n    Get returns the slice of values set by this flag\n\nfunc (i *SliceBase[T, C, VC]) Serialize() string\n    Serialize allows SliceBase to fulfill Serializer\n\nfunc (i *SliceBase[T, C, VC]) Set(value string) error\n    Set parses the value and appends it to the list of values\n\nfunc (i *SliceBase[T, C, VC]) String() string\n    String returns a readable representation of this value (for usage defaults)\n\nfunc (i SliceBase[T, C, VC]) ToString(t []T) string\n\nfunc (i *SliceBase[T, C, VC]) Value() []T\n    Value returns the slice of values set by this flag\n\ntype StringArg = ArgumentBase[string, StringConfig, stringValue]\n\ntype StringArgs = ArgumentsBase[string, StringConfig, stringValue]\n\ntype StringConfig struct {\n\t// Whether to trim whitespace of parsed value\n\tTrimSpace bool\n}\n    StringConfig defines the configuration for string flags\n\ntype StringFlag = FlagBase[string, StringConfig, stringValue]\n\ntype StringMap = MapBase[string, StringConfig, stringValue]\n\ntype StringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap]\n\ntype StringMapFlag = FlagBase[map[string]string, StringConfig, StringMap]\n\ntype StringSlice = SliceBase[string, StringConfig, stringValue]\n\ntype StringSliceFlag = FlagBase[[]string, StringConfig, StringSlice]\n\ntype SuggestCommandFunc func(commands []*Command, provided string) string\n\ntype SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string\n\ntype TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue]\n\ntype TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue]\n\ntype TimestampConfig struct {\n\tTimezone *time.Location\n\t// Available layouts for flag value.\n\t//\n\t// Note that value for formats with missing year/date will be interpreted as current year/date respectively.\n\t//\n\t// Read more about time layouts: https://pkg.go.dev/time#pkg-constants\n\tLayouts []string\n}\n    TimestampConfig defines the config for timestamp flags\n\ntype TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampValue]\n\ntype Uint16Arg = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16Args = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16Flag = FlagBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16Slice = SliceBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16SliceFlag = FlagBase[[]uint16, IntegerConfig, Uint16Slice]\n\ntype Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32Args = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32Flag = FlagBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32Slice = SliceBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32SliceFlag = FlagBase[[]uint32, IntegerConfig, Uint32Slice]\n\ntype Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64Args = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64Flag = FlagBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64Slice = SliceBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64SliceFlag = FlagBase[[]uint64, IntegerConfig, Uint64Slice]\n\ntype Uint8Arg = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8Args = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8Flag = FlagBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8Slice = SliceBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8SliceFlag = FlagBase[[]uint8, IntegerConfig, Uint8Slice]\n\ntype UintArg = ArgumentBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintArgs = ArgumentsBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintFlag = FlagBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintSlice = SliceBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintSliceFlag = FlagBase[[]uint, IntegerConfig, UintSlice]\n\ntype Value interface {\n\tflag.Value\n\tflag.Getter\n}\n    Value represents a value as used by cli. For now it implements the golang\n    flag.Value interface\n\ntype ValueCreator[T any, C any] interface {\n\tCreate(T, *T, C) Value\n\tToString(T) string\n}\n    ValueCreator is responsible for creating a flag.Value emulation as well as\n    custom formatting\n\n        T specifies the type\n        C specifies the config for the type\n\ntype ValueSource interface {\n\tfmt.Stringer\n\tfmt.GoStringer\n\n\t// Lookup returns the value from the source and if it was found\n\t// or returns an empty string and false\n\tLookup() (string, bool)\n}\n    ValueSource is a source which can be used to look up a value, typically for\n    use with a cli.Flag\n\nfunc EnvVar(key string) ValueSource\n\nfunc File(path string) ValueSource\n\nfunc NewMapValueSource(key string, ms MapSource) ValueSource\n\ntype ValueSourceChain struct {\n\tChain []ValueSource\n}\n    ValueSourceChain contains an ordered series of ValueSource that allows for\n    lookup where the first ValueSource to resolve is returned\n\nfunc EnvVars(keys ...string) ValueSourceChain\n    EnvVars is a helper function to encapsulate a number of envVarValueSource\n    together as a ValueSourceChain\n\nfunc Files(paths ...string) ValueSourceChain\n    Files is a helper function to encapsulate a number of fileValueSource\n    together as a ValueSourceChain\n\nfunc NewValueSourceChain(src ...ValueSource) ValueSourceChain\n\nfunc (vsc *ValueSourceChain) Append(other ValueSourceChain)\n\nfunc (vsc *ValueSourceChain) EnvKeys() []string\n\nfunc (vsc *ValueSourceChain) GoString() string\n\nfunc (vsc *ValueSourceChain) Lookup() (string, bool)\n\nfunc (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool)\n\nfunc (vsc *ValueSourceChain) String() string\n\ntype VisibleFlag interface {\n\t// IsVisible returns true if the flag is not hidden, otherwise false\n\tIsVisible() bool\n}\n    VisibleFlag is an interface that allows to check if a flag is visible\n\ntype VisibleFlagCategory interface {\n\t// Name returns the category name string\n\tName() string\n\t// Flags returns a slice of VisibleFlag sorted by name\n\tFlags() []Flag\n}\n    VisibleFlagCategory is a category containing flags.\n\n"
  },
  {
    "path": "help.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"text/template\"\n\t\"unicode/utf8\"\n)\n\nconst (\n\thelpName  = \"help\"\n\thelpAlias = \"h\"\n)\n\n// HelpPrinterFunc prints help for the Command.\ntype HelpPrinterFunc func(w io.Writer, templ string, data any)\n\n// Prints help for the Command with custom template function.\ntype HelpPrinterCustomFunc func(w io.Writer, templ string, data any, customFunc map[string]any)\n\n// HelpPrinter is a function that writes the help output. If not set explicitly,\n// this calls HelpPrinterCustom using only the default template functions.\n//\n// If custom logic for printing help is required, this function can be\n// overridden. If the ExtraInfo field is defined on a Command, this function\n// should not be modified, as HelpPrinterCustom will be used directly in order\n// to capture the extra information.\nvar HelpPrinter HelpPrinterFunc = DefaultPrintHelp\n\n// HelpPrinterCustom is a function that writes the help output. It is used as\n// the default implementation of HelpPrinter, and may be called directly if\n// the ExtraInfo field is set on a Command.\n//\n// In the default implementation, if the customFuncs argument contains a\n// \"wrapAt\" key, which is a function which takes no arguments and returns\n// an int, this int value will be used to produce a \"wrap\" function used\n// by the default template to wrap long lines.\nvar HelpPrinterCustom HelpPrinterCustomFunc = DefaultPrintHelpCustom\n\n// VersionPrinter prints the version for the root Command.\nvar VersionPrinter = DefaultPrintVersion\n\n// ShowRootCommandHelp is an action that displays help for the root command.\nvar ShowRootCommandHelp = DefaultShowRootCommandHelp\n\n// ShowAppHelp is a backward-compatible name for ShowRootCommandHelp.\nvar ShowAppHelp = ShowRootCommandHelp\n\n// ShowCommandHelp prints help for the given command\nvar ShowCommandHelp = DefaultShowCommandHelp\n\n// ShowSubcommandHelp prints help for the given subcommand\nvar ShowSubcommandHelp = DefaultShowSubcommandHelp\n\n// UsageCommandHelp is the text to override the USAGE section of the help command\nvar UsageCommandHelp = \"Shows a list of commands or help for one command\"\n\n// ArgsUsageCommandHelp is a short description of the arguments of the help command\nvar ArgsUsageCommandHelp = \"[command]\"\n\nfunc buildHelpCommand(withAction bool) *Command {\n\tcmd := &Command{\n\t\tName:      helpName,\n\t\tAliases:   []string{helpAlias},\n\t\tUsage:     UsageCommandHelp,\n\t\tArgsUsage: ArgsUsageCommandHelp,\n\t\tHideHelp:  true,\n\t}\n\n\tif withAction {\n\t\tcmd.Action = helpCommandAction\n\t}\n\n\treturn cmd\n}\n\nfunc helpCommandAction(ctx context.Context, cmd *Command) error {\n\targs := cmd.Args()\n\tfirstArg := args.First()\n\n\ttracef(\"doing help for cmd %[1]q with args %[2]q\", cmd, args)\n\n\t// This action can be triggered by a \"default\" action of a command\n\t// or via cmd.Run when cmd == helpCmd. So we have following possibilities\n\t//\n\t// 1 $ app\n\t// 2 $ app help\n\t// 3 $ app foo\n\t// 4 $ app help foo\n\t// 5 $ app foo help\n\n\t// Case 4. when executing a help command set the context to parent\n\t// to allow resolution of subsequent args. This will transform\n\t// $ app help foo\n\t//     to\n\t// $ app foo\n\t// which will then be handled as case 3\n\tif cmd.parent != nil && (cmd.HasName(helpName) || cmd.HasName(helpAlias)) {\n\t\ttracef(\"setting cmd to cmd.parent\")\n\t\tcmd = cmd.parent\n\t}\n\n\t// Case 4. $ app help foo\n\t// foo is the command for which help needs to be shown\n\tif firstArg != \"\" {\n\t\t/*\tif firstArg == \"--\" {\n\t\t\treturn nil\n\t\t}*/\n\t\ttracef(\"returning ShowCommandHelp with %[1]q\", firstArg)\n\t\treturn ShowCommandHelp(ctx, cmd, firstArg)\n\t}\n\n\t// Case 1 & 2\n\t// Special case when running help on main app itself as opposed to individual\n\t// commands/subcommands\n\tif cmd.parent == nil {\n\t\ttracef(\"returning ShowRootCommandHelp\")\n\t\t_ = ShowRootCommandHelp(cmd)\n\t\treturn nil\n\t}\n\n\t// Case 3, 5\n\tif len(cmd.VisibleCommands()) == 0 {\n\n\t\ttmpl := cmd.CustomHelpTemplate\n\t\tif tmpl == \"\" {\n\t\t\ttmpl = CommandHelpTemplate\n\t\t}\n\n\t\ttracef(\"running HelpPrinter with command %[1]q\", cmd.Name)\n\t\tHelpPrinter(cmd.Root().Writer, tmpl, cmd)\n\n\t\treturn nil\n\t}\n\n\ttracef(\"running ShowSubcommandHelp\")\n\treturn ShowSubcommandHelp(cmd)\n}\n\n// ShowRootCommandHelpAndExit prints the list of subcommands and exits with exit code.\nfunc ShowRootCommandHelpAndExit(cmd *Command, exitCode int) {\n\t_ = ShowRootCommandHelp(cmd)\n\tOsExiter(exitCode)\n}\n\n// ShowAppHelpAndExit is a backward-compatible name for ShowRootCommandHelp.\nvar ShowAppHelpAndExit = ShowRootCommandHelpAndExit\n\n// DefaultShowRootCommandHelp is the default implementation of ShowRootCommandHelp.\nfunc DefaultShowRootCommandHelp(cmd *Command) error {\n\ttmpl := cmd.CustomRootCommandHelpTemplate\n\tif tmpl == \"\" {\n\t\ttracef(\"using RootCommandHelpTemplate\")\n\t\ttmpl = RootCommandHelpTemplate\n\t}\n\n\tif cmd.ExtraInfo == nil {\n\t\tHelpPrinter(cmd.Root().Writer, tmpl, cmd.Root())\n\t\treturn nil\n\t}\n\n\ttracef(\"setting ExtraInfo in customAppData\")\n\tcustomAppData := func() map[string]any {\n\t\treturn map[string]any{\n\t\t\t\"ExtraInfo\": cmd.ExtraInfo,\n\t\t}\n\t}\n\tHelpPrinterCustom(cmd.Root().Writer, tmpl, cmd.Root(), customAppData())\n\n\treturn nil\n}\n\n// DefaultRootCommandComplete prints the list of subcommands as the default completion method.\nfunc DefaultRootCommandComplete(ctx context.Context, cmd *Command) {\n\tDefaultCompleteWithFlags(ctx, cmd)\n}\n\n// DefaultAppComplete is a backward-compatible name for DefaultRootCommandComplete.\nvar DefaultAppComplete = DefaultRootCommandComplete\n\nfunc printCommandSuggestions(commands []*Command, writer io.Writer) {\n\tshell := os.Getenv(\"SHELL\")\n\tfor _, command := range commands {\n\t\tif command.Hidden {\n\t\t\tcontinue\n\t\t}\n\t\tif (strings.HasSuffix(shell, \"zsh\") || strings.HasSuffix(shell, \"fish\")) && len(command.Usage) > 0 {\n\t\t\t_, _ = fmt.Fprintf(writer, \"%s:%s\\n\", command.Name, command.Usage)\n\t\t} else {\n\t\t\t_, _ = fmt.Fprintf(writer, \"%s\\n\", command.Name)\n\t\t}\n\t}\n}\n\nfunc cliArgContains(flagName string, args []string) bool {\n\tfor _, name := range strings.Split(flagName, \",\") {\n\t\tname = strings.TrimSpace(name)\n\t\tcount := utf8.RuneCountInString(name)\n\t\tif count > 2 {\n\t\t\tcount = 2\n\t\t}\n\t\tflag := fmt.Sprintf(\"%s%s\", strings.Repeat(\"-\", count), name)\n\t\tfor _, a := range args {\n\t\t\tif a == flag {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {\n\t// Trim to handle both \"-short\" and \"--long\" flags.\n\tcur := strings.TrimLeft(lastArg, \"-\")\n\tfor _, flag := range flags {\n\t\tif bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden {\n\t\t\tcontinue\n\t\t}\n\n\t\tusage := \"\"\n\t\tif docFlag, ok := flag.(DocGenerationFlag); ok {\n\t\t\tusage = docFlag.GetUsage()\n\t\t}\n\n\t\tname := strings.TrimSpace(flag.Names()[0])\n\t\t// this will get total count utf8 letters in flag name\n\t\tcount := utf8.RuneCountInString(name)\n\t\tif count > 2 {\n\t\t\tcount = 2 // reuse this count to generate single - or -- in flag completion\n\t\t}\n\t\t// if flag name has more than one utf8 letter and last argument in cli has -- prefix then\n\t\t// skip flag completion for short flags example -v or -x\n\t\tif strings.HasPrefix(lastArg, \"--\") && count == 1 {\n\t\t\tcontinue\n\t\t}\n\t\t// match if last argument matches this flag and it is not repeated\n\t\tif strings.HasPrefix(name, cur) && cur != name /* && !cliArgContains(name, os.Args)*/ {\n\t\t\tflagCompletion := fmt.Sprintf(\"%s%s\", strings.Repeat(\"-\", count), name)\n\t\t\tshell := os.Getenv(\"SHELL\")\n\t\t\tif usage != \"\" && (strings.HasSuffix(shell, \"zsh\") || strings.HasSuffix(shell, \"fish\")) {\n\t\t\t\tflagCompletion = fmt.Sprintf(\"%s:%s\", flagCompletion, usage)\n\t\t\t}\n\t\t\tfmt.Fprintln(writer, flagCompletion)\n\t\t}\n\t}\n}\n\nfunc DefaultCompleteWithFlags(ctx context.Context, cmd *Command) {\n\targs := os.Args\n\tif cmd != nil && cmd.parent != nil {\n\t\targs = cmd.Args().Slice()\n\t\ttracef(\"running default complete with flags[%v] on command %[2]q\", args, cmd.Name)\n\t} else {\n\t\ttracef(\"running default complete with os.Args flags[%v]\", args)\n\t}\n\targsLen := len(args)\n\tlastArg := \"\"\n\t// parent command will have --generate-shell-completion so we need\n\t// to account for that\n\tif argsLen > 1 {\n\t\tlastArg = args[argsLen-2]\n\t} else if argsLen > 0 {\n\t\tlastArg = args[argsLen-1]\n\t}\n\n\tif lastArg == \"--\" {\n\t\ttracef(\"No completions due to termination\")\n\t\treturn\n\t}\n\n\tif lastArg == completionFlag {\n\t\tlastArg = \"\"\n\t}\n\n\tif strings.HasPrefix(lastArg, \"-\") {\n\t\ttracef(\"printing flag suggestion for flag[%v] on command %[1]q\", lastArg, cmd.Name)\n\t\tprintFlagSuggestions(lastArg, cmd.Flags, cmd.Root().Writer)\n\t\treturn\n\t}\n\n\tif cmd != nil {\n\t\ttracef(\"printing command suggestions on command %[1]q\", cmd.Name)\n\t\tprintCommandSuggestions(cmd.Commands, cmd.Root().Writer)\n\t\treturn\n\t}\n}\n\n// ShowCommandHelpAndExit exits with code after showing help via ShowCommandHelp.\nfunc ShowCommandHelpAndExit(ctx context.Context, cmd *Command, command string, code int) {\n\t_ = ShowCommandHelp(ctx, cmd, command)\n\tOsExiter(code)\n}\n\n// DefaultShowCommandHelp is the default implementation of ShowCommandHelp.\nfunc DefaultShowCommandHelp(ctx context.Context, cmd *Command, commandName string) error {\n\tfor _, subCmd := range cmd.Commands {\n\t\tif !subCmd.HasName(commandName) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttmpl := subCmd.CustomHelpTemplate\n\t\tif tmpl == \"\" {\n\t\t\tif len(subCmd.Commands) == 0 {\n\t\t\t\ttracef(\"using CommandHelpTemplate\")\n\t\t\t\ttmpl = CommandHelpTemplate\n\t\t\t} else {\n\t\t\t\ttracef(\"using SubcommandHelpTemplate\")\n\t\t\t\ttmpl = SubcommandHelpTemplate\n\t\t\t}\n\t\t}\n\n\t\ttracef(\"running HelpPrinter\")\n\t\tHelpPrinter(cmd.Root().Writer, tmpl, subCmd)\n\n\t\ttracef(\"returning nil after printing help\")\n\t\treturn nil\n\t}\n\n\ttracef(\"no matching command found\")\n\n\tif cmd.CommandNotFound == nil {\n\t\terrMsg := fmt.Sprintf(\"No help topic for '%v'\", commandName)\n\n\t\tif cmd.Suggest {\n\t\t\tif suggestion := SuggestCommand(cmd.Commands, commandName); suggestion != \"\" {\n\t\t\t\terrMsg += \". \" + suggestion\n\t\t\t}\n\t\t}\n\n\t\ttracef(\"exiting 3 with errMsg %[1]q\", errMsg)\n\t\treturn Exit(errMsg, 3)\n\t}\n\n\ttracef(\"running CommandNotFound func for %[1]q\", commandName)\n\tcmd.CommandNotFound(ctx, cmd, commandName)\n\n\treturn nil\n}\n\n// ShowSubcommandHelpAndExit prints help for the given subcommand via ShowSubcommandHelp and exits with exit code.\nfunc ShowSubcommandHelpAndExit(cmd *Command, exitCode int) {\n\t_ = ShowSubcommandHelp(cmd)\n\tOsExiter(exitCode)\n}\n\n// DefaultShowSubcommandHelp is the default implementation of ShowSubcommandHelp.\nfunc DefaultShowSubcommandHelp(cmd *Command) error {\n\tHelpPrinter(cmd.Root().Writer, SubcommandHelpTemplate, cmd)\n\treturn nil\n}\n\n// ShowVersion prints the version number of the root Command.\nfunc ShowVersion(cmd *Command) {\n\ttracef(\"showing version via VersionPrinter (cmd=%[1]q)\", cmd.Name)\n\tVersionPrinter(cmd)\n}\n\n// DefaultPrintVersion is the default implementation of VersionPrinter.\nfunc DefaultPrintVersion(cmd *Command) {\n\t_, _ = fmt.Fprintf(cmd.Root().Writer, \"%v version %v\\n\", cmd.Name, cmd.Version)\n}\n\nfunc handleTemplateError(err error) {\n\tif err != nil {\n\t\ttracef(\"error encountered during template parse: %[1]v\", err)\n\t\t// If the writer is closed, t.Execute will fail, and there's nothing\n\t\t// we can do to recover.\n\t\tif os.Getenv(\"CLI_TEMPLATE_ERROR_DEBUG\") != \"\" {\n\t\t\t_, _ = fmt.Fprintf(ErrWriter, \"CLI TEMPLATE ERROR: %#v\\n\", err)\n\t\t}\n\t\treturn\n\t}\n}\n\n// DefaultPrintHelpCustom is the default implementation of HelpPrinterCustom.\n//\n// The customFuncs map will be combined with a default template.FuncMap to\n// allow using arbitrary functions in template rendering.\nfunc DefaultPrintHelpCustom(out io.Writer, templ string, data any, customFuncs map[string]any) {\n\tconst maxLineLength = 10000\n\n\ttracef(\"building default funcMap\")\n\tfuncMap := template.FuncMap{\n\t\t\"join\":           strings.Join,\n\t\t\"subtract\":       subtract,\n\t\t\"indent\":         indent,\n\t\t\"nindent\":        nindent,\n\t\t\"trim\":           strings.TrimSpace,\n\t\t\"wrap\":           func(input string, offset int) string { return wrap(input, offset, maxLineLength) },\n\t\t\"offset\":         offset,\n\t\t\"offsetCommands\": offsetCommands,\n\t}\n\n\tif wa, ok := customFuncs[\"wrapAt\"]; ok {\n\t\tif wrapAtFunc, ok := wa.(func() int); ok {\n\t\t\twrapAt := wrapAtFunc()\n\t\t\tcustomFuncs[\"wrap\"] = func(input string, offset int) string {\n\t\t\t\treturn wrap(input, offset, wrapAt)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor key, value := range customFuncs {\n\t\tfuncMap[key] = value\n\t}\n\n\tw := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)\n\tt := template.Must(template.New(\"help\").Funcs(funcMap).Parse(templ))\n\n\tif _, err := t.New(\"helpNameTemplate\").Parse(helpNameTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"argsTemplate\").Parse(argsTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"usageTemplate\").Parse(usageTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"descriptionTemplate\").Parse(descriptionTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"visibleCommandTemplate\").Parse(visibleCommandTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"copyrightTemplate\").Parse(copyrightTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"versionTemplate\").Parse(versionTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"visibleFlagCategoryTemplate\").Parse(visibleFlagCategoryTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"visibleFlagTemplate\").Parse(visibleFlagTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"visiblePersistentFlagTemplate\").Parse(visiblePersistentFlagTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"visibleGlobalFlagCategoryTemplate\").Parse(strings.ReplaceAll(visibleFlagCategoryTemplate, \"OPTIONS\", \"GLOBAL OPTIONS\")); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"authorsTemplate\").Parse(authorsTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\tif _, err := t.New(\"visibleCommandCategoryTemplate\").Parse(visibleCommandCategoryTemplate); err != nil {\n\t\thandleTemplateError(err)\n\t}\n\n\ttracef(\"executing template\")\n\thandleTemplateError(t.Execute(w, data))\n\n\t_ = w.Flush()\n}\n\n// DefaultPrintHelp is the default implementation of HelpPrinter.\nfunc DefaultPrintHelp(out io.Writer, templ string, data any) {\n\tHelpPrinterCustom(out, templ, data, nil)\n}\n\nfunc checkVersion(cmd *Command) bool {\n\tfound := false\n\tfor _, name := range VersionFlag.Names() {\n\t\tif cmd.Bool(name) {\n\t\t\tfound = true\n\t\t}\n\t}\n\treturn found\n}\n\nfunc checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) {\n\tif (c.parent == nil && !c.EnableShellCompletion) || (c.parent != nil && !c.Root().shellCompletion) {\n\t\treturn false, arguments\n\t}\n\n\tpos := len(arguments) - 1\n\tlastArg := arguments[pos]\n\n\tif lastArg != completionFlag {\n\t\treturn false, arguments\n\t}\n\n\tfor _, arg := range arguments {\n\t\t// If arguments include \"--\", shell completion is disabled\n\t\t// because after \"--\" only positional arguments are accepted.\n\t\t// https://unix.stackexchange.com/a/11382\n\t\tif arg == \"--\" {\n\t\t\treturn false, arguments[:pos]\n\t\t}\n\t}\n\n\treturn true, arguments[:pos]\n}\n\nfunc checkCompletions(ctx context.Context, cmd *Command) bool {\n\ttracef(\"checking completions on command %[1]q\", cmd.Name)\n\n\tif !cmd.Root().shellCompletion {\n\t\ttracef(\"completion not enabled skipping %[1]q\", cmd.Name)\n\t\treturn false\n\t}\n\n\tif argsArguments := cmd.Args(); argsArguments.Present() {\n\t\tname := argsArguments.First()\n\t\tif cmd := cmd.Command(name); cmd != nil {\n\t\t\t// let the command handle the completion\n\t\t\treturn false\n\t\t}\n\t}\n\n\ttracef(\"no subcommand found for completion %[1]q\", cmd.Name)\n\n\tif cmd.ShellComplete != nil {\n\t\ttracef(\"running shell completion func for command %[1]q\", cmd.Name)\n\t\tcmd.ShellComplete(ctx, cmd)\n\t}\n\n\treturn true\n}\n\nfunc subtract(a, b int) int {\n\treturn a - b\n}\n\nfunc indent(spaces int, v string) string {\n\tpad := strings.Repeat(\" \", spaces)\n\treturn pad + strings.ReplaceAll(v, \"\\n\", \"\\n\"+pad)\n}\n\nfunc nindent(spaces int, v string) string {\n\treturn \"\\n\" + indent(spaces, v)\n}\n\nfunc wrap(input string, offset int, wrapAt int) string {\n\tvar ss []string\n\n\tlines := strings.Split(input, \"\\n\")\n\n\tpadding := strings.Repeat(\" \", offset)\n\n\tfor i, line := range lines {\n\t\tif line == \"\" {\n\t\t\tss = append(ss, line)\n\t\t} else {\n\t\t\twrapped := wrapLine(line, offset, wrapAt, padding)\n\t\t\tif i == 0 {\n\t\t\t\tss = append(ss, wrapped)\n\t\t\t} else {\n\t\t\t\tss = append(ss, padding+wrapped)\n\t\t\t}\n\n\t\t}\n\t}\n\n\treturn strings.Join(ss, \"\\n\")\n}\n\nfunc wrapLine(input string, offset int, wrapAt int, padding string) string {\n\tif wrapAt <= offset || len(input) <= wrapAt-offset {\n\t\treturn input\n\t}\n\n\tlineWidth := wrapAt - offset\n\twords := strings.Fields(input)\n\tif len(words) == 0 {\n\t\treturn input\n\t}\n\n\twrapped := words[0]\n\tspaceLeft := lineWidth - len(wrapped)\n\tfor _, word := range words[1:] {\n\t\tif len(word)+1 > spaceLeft {\n\t\t\twrapped += \"\\n\" + padding + word\n\t\t\tspaceLeft = lineWidth - len(word)\n\t\t} else {\n\t\t\twrapped += \" \" + word\n\t\t\tspaceLeft -= 1 + len(word)\n\t\t}\n\t}\n\n\treturn wrapped\n}\n\nfunc offset(input string, fixed int) int {\n\treturn len(input) + fixed\n}\n\n// this function tries to find the max width of the names column\n// so say we have the following rows for help\n//\n//\tfoo1, foo2, foo3  some string here\n//\tbar1, b2 some other string here\n//\n// We want to offset the 2nd row usage by some amount so that everything\n// is aligned\n//\n//\tfoo1, foo2, foo3  some string here\n//\tbar1, b2          some other string here\n//\n// to find that offset we find the length of all the rows and use the max\n// to calculate the offset\nfunc offsetCommands(cmds []*Command, fixed int) int {\n\tmax := 0\n\tfor _, cmd := range cmds {\n\t\ts := strings.Join(cmd.Names(), \", \")\n\t\tif len(s) > max {\n\t\t\tmax = len(s)\n\t\t}\n\t}\n\treturn max + fixed\n}\n"
  },
  {
    "path": "help_test.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_ShowRootCommandHelp_NoAuthor(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{Writer: output}\n\t_ = ShowRootCommandHelp(cmd)\n\n\tif bytes.Contains(output.Bytes(), []byte(\"AUTHOR(S):\")) {\n\t\tt.Errorf(\"expected\\n%snot to include %s\", output.String(), \"AUTHOR(S):\")\n\t}\n}\n\nfunc Test_ShowRootCommandHelp_NoVersion(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{Writer: output}\n\n\tcmd.Version = \"\"\n\n\t_ = ShowRootCommandHelp(cmd)\n\n\tif bytes.Contains(output.Bytes(), []byte(\"VERSION:\")) {\n\t\tt.Errorf(\"expected\\n%snot to include %s\", output.String(), \"VERSION:\")\n\t}\n}\n\nfunc Test_ShowRootCommandHelp_HideVersion(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{Writer: output}\n\n\tcmd.HideVersion = true\n\n\t_ = ShowRootCommandHelp(cmd)\n\n\tif bytes.Contains(output.Bytes(), []byte(\"VERSION:\")) {\n\t\tt.Errorf(\"expected\\n%snot to include %s\", output.String(), \"VERSION:\")\n\t}\n}\n\nfunc Test_ShowRootCommandHelp_MultiLineDescription(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{Writer: output}\n\n\tcmd.HideVersion = true\n\tcmd.Description = \"multi\\n  line\"\n\n\t_ = ShowRootCommandHelp(cmd)\n\n\tif !bytes.Contains(output.Bytes(), []byte(\"DESCRIPTION:\\n   multi\\n     line\")) {\n\t\tt.Errorf(\"expected\\n%s\\nto include\\n%s\", output.String(), \"DESCRIPTION:\\n   multi\\n     line\")\n\t}\n}\n\nfunc TestShowCommandHelpAndExit(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:   \"ok\",\n\t\t\t\tWriter: output,\n\t\t\t},\n\t\t},\n\t\tWriter: output,\n\t}\n\n\tShowCommandHelpAndExit(context.Background(), cmd, \"ok\", 42)\n\n\trequire.Equal(t, 42, lastExitCode)\n}\n\nfunc TestShowRootCommandHelpAndExit(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{Writer: output}\n\n\tShowRootCommandHelpAndExit(cmd, 42)\n\n\trequire.Equal(t, 42, lastExitCode)\n}\n\nfunc TestShowSubcommandHelpAndExit(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\tok := &Command{\n\t\tName:   \"ok\",\n\t\tWriter: output,\n\t}\n\tcmd := &Command{\n\t\tCommands: []*Command{ok},\n\t\tWriter:   output,\n\t}\n\t_ = cmd\n\n\tShowSubcommandHelpAndExit(ok, 42)\n\n\trequire.Equal(t, 42, lastExitCode)\n}\n\nfunc Test_HelpFlag_RequiredFlagsNoDefault(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"foo\", Aliases: []string{\"f\"}, Required: true},\n\t\t},\n\t\tArguments: AnyArguments,\n\t\tWriter:    output,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"test\", \"-h\"})\n\n\texpected := `NAME:\n   test - A new cli application\n\nUSAGE:\n   test [global options] [arguments...]\n\nGLOBAL OPTIONS:\n   --foo int, -f int  \n   --help, -h         show help\n`\n\n\tassert.Contains(t, output.String(), expected,\n\t\t\"expected output to include usage text\")\n}\n\nfunc Test_HelpCommand_RequiredFlagsNoDefault(t *testing.T) {\n\toutput := new(bytes.Buffer)\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&Int64Flag{Name: \"foo\", Aliases: []string{\"f\"}, Required: true},\n\t\t},\n\t\tArguments: AnyArguments,\n\t\tWriter:    output,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"test\", \"help\"})\n\n\texpected := `NAME:\n   test - A new cli application\n\nUSAGE:\n   test [global options] [arguments...]\n\nGLOBAL OPTIONS:\n   --foo int, -f int  \n   --help, -h         show help\n`\n\n\tassert.Contains(t, output.String(), expected,\n\t\t\"expected output to include usage text\")\n}\n\nfunc Test_Help_Custom_Flags(t *testing.T) {\n\toldFlag := HelpFlag\n\tdefer func() {\n\t\tHelpFlag = oldFlag\n\t}()\n\n\tHelpFlag = &BoolFlag{\n\t\tName:    \"help\",\n\t\tAliases: []string{\"x\"},\n\t\tUsage:   \"show help\",\n\t}\n\n\tout := &bytes.Buffer{}\n\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"foo\", Aliases: []string{\"h\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.True(t, cmd.Bool(\"h\"), \"custom help flag not set\")\n\t\t\treturn nil\n\t\t},\n\t\tWriter: out,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"test\", \"-h\"})\n\trequire.Len(t, out.String(), 0)\n}\n\nfunc Test_Help_Nil_Flags(t *testing.T) {\n\toldFlag := HelpFlag\n\tdefer func() {\n\t\tHelpFlag = oldFlag\n\t}()\n\tHelpFlag = nil\n\n\tcmd := &Command{\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\treturn nil\n\t\t},\n\t}\n\tout := new(bytes.Buffer)\n\tcmd.Writer = out\n\t_ = cmd.Run(buildTestContext(t), []string{\"test\"})\n\trequire.Len(t, out.String(), 0)\n}\n\nfunc Test_Version_Custom_Flags(t *testing.T) {\n\toldFlag := VersionFlag\n\tdefer func() {\n\t\tVersionFlag = oldFlag\n\t}()\n\n\tVersionFlag = &BoolFlag{\n\t\tName:    \"version\",\n\t\tAliases: []string{\"V\"},\n\t\tUsage:   \"show version\",\n\t}\n\n\tout := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{Name: \"foo\", Aliases: []string{\"v\"}},\n\t\t},\n\t\tAction: func(_ context.Context, cmd *Command) error {\n\t\t\tassert.True(t, cmd.Bool(\"v\"), \"custom version flag not set\")\n\t\t\treturn nil\n\t\t},\n\t\tWriter: out,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"test\", \"-v\"})\n\trequire.Len(t, out.String(), 0)\n}\n\nfunc Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {\n\tcmd := &Command{}\n\n\t_ = cmd.Run(context.Background(), []string{\"foo\", \"bar\"})\n\n\terr := helpCommandAction(context.Background(), cmd)\n\trequire.Error(t, err, \"expected error from helpCommandAction()\")\n\n\texitErr, ok := err.(*exitError)\n\trequire.True(t, ok, \"expected *exitError from helpCommandAction()\")\n\n\trequire.Contains(t, exitErr.Error(), \"No help topic for\", \"expected an unknown help topic error\")\n\trequire.Equal(t, 3, exitErr.exitCode, \"expected exit value = 3\")\n}\n\nfunc Test_helpCommand_InHelpOutput(t *testing.T) {\n\tcmd := &Command{}\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"test\", \"--help\"})\n\n\ts := output.String()\n\n\trequire.NotContains(t, s, \"\\nCOMMANDS:\\nGLOBAL OPTIONS:\\n\", \"empty COMMANDS section detected\")\n\trequire.Contains(t, s, \"--help, -h\", \"missing \\\"--help, --h\\\"\")\n}\n\nfunc TestHelpCommand_FullName(t *testing.T) {\n\ttestCases := []struct {\n\t\tname     string\n\t\targs     []string\n\t\tcontains string\n\t\tskip     bool\n\t}{\n\t\t{\n\t\t\tname:     \"app help's FullName\",\n\t\t\targs:     []string{\"app\", \"help\", \"help\"},\n\t\t\tcontains: \"app help -\",\n\t\t},\n\t\t{\n\t\t\tname:     \"app help's FullName via flag\",\n\t\t\targs:     []string{\"app\", \"-h\", \"help\"},\n\t\t\tcontains: \"app help -\",\n\t\t},\n\t\t{\n\t\t\tname:     \"cmd help's FullName\",\n\t\t\targs:     []string{\"app\", \"cmd\", \"help\", \"help\"},\n\t\t\tcontains: \"app cmd help -\",\n\t\t\tskip:     true, // FIXME: App Command collapse\n\t\t},\n\t\t{\n\t\t\tname:     \"cmd help's FullName via flag\",\n\t\t\targs:     []string{\"app\", \"cmd\", \"-h\", \"help\"},\n\t\t\tcontains: \"app cmd help -\",\n\t\t\tskip:     true, // FIXME: App Command collapse\n\t\t},\n\t\t{\n\t\t\tname:     \"subcmd help's FullName\",\n\t\t\targs:     []string{\"app\", \"cmd\", \"subcmd\", \"help\", \"help\"},\n\t\t\tcontains: \"app cmd subcmd help -\",\n\t\t},\n\t\t{\n\t\t\tname:     \"subcmd help's FullName via flag\",\n\t\t\targs:     []string{\"app\", \"cmd\", \"subcmd\", \"-h\", \"help\"},\n\t\t\tcontains: \"app cmd subcmd help -\",\n\t\t},\n\t}\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tout := &bytes.Buffer{}\n\n\t\t\tif tc.skip {\n\t\t\t\tt.SkipNow()\n\t\t\t}\n\n\t\t\tcmd := &Command{\n\t\t\t\tName: \"app\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"subcmd\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tWriter:    out,\n\t\t\t\tErrWriter: out,\n\t\t\t}\n\n\t\t\tr := require.New(t)\n\t\t\tr.NoError(cmd.Run(buildTestContext(t), tc.args))\n\t\t\tr.Contains(out.String(), tc.contains)\n\t\t})\n\t}\n}\n\nfunc Test_helpCommand_HideHelpCommand(t *testing.T) {\n\tbuf := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tName:   \"app\",\n\t\tWriter: buf,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"app\", \"help\", \"help\"})\n\tassert.NoError(t, err)\n\tgot := buf.String()\n\tnotWant := \"COMMANDS:\"\n\tassert.NotContains(t, got, notWant)\n}\n\nfunc Test_helpCommand_HideHelpFlag(t *testing.T) {\n\tcmd := buildMinimalTestCommand()\n\tcmd.HideHelp = true\n\n\tassert.Error(t, cmd.Run(buildTestContext(t), []string{\"app\", \"help\", \"-h\"}), \"Expected flag error - Got nil\")\n}\n\nfunc Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {\n\tcmd := &Command{}\n\t_ = cmd.Run(context.Background(), []string{\"foo\", \"bar\"})\n\n\terr := helpCommandAction(context.Background(), cmd)\n\trequire.Error(t, err, \"expected error from helpCommandAction(), but got nil\")\n\n\texitErr, ok := err.(*exitError)\n\trequire.True(t, ok, \"expected *exitError from helpCommandAction(), but instead got: %v\", err.Error())\n\n\trequire.Contains(t, exitErr.Error(), \"No help topic for\", \"expected an unknown help topic error\")\n\trequire.Equal(t, 3, exitErr.exitCode, \"unexpected exit value\")\n}\n\nfunc TestShowRootCommandHelp_CommandAliases(t *testing.T) {\n\tout := &bytes.Buffer{}\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:    \"frobbly\",\n\t\t\t\tAliases: []string{\"fr\", \"frob\"},\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tWriter: out,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"--help\"})\n\trequire.Contains(t, out.String(), \"frobbly, fr, frob\")\n}\n\nfunc TestShowCommandHelp_AppendHelp(t *testing.T) {\n\ttestCases := []struct {\n\t\tname            string\n\t\thideHelp        bool\n\t\thideHelpCommand bool\n\t\targs            []string\n\t\tverify          func(*testing.T, string)\n\t}{\n\t\t{\n\t\t\tname:     \"with HideHelp\",\n\t\t\thideHelp: true,\n\t\t\targs:     []string{\"app\", \"help\"},\n\t\t\tverify: func(t *testing.T, outString string) {\n\t\t\t\tr := require.New(t)\n\t\t\t\tr.NotContains(outString, \"help, h  Shows a list of commands or help for one command\")\n\t\t\t\tr.NotContains(outString, \"--help, -h  show help\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"with HideHelpCommand\",\n\t\t\thideHelpCommand: true,\n\t\t\targs:            []string{\"app\", \"--help\"},\n\t\t\tverify: func(t *testing.T, outString string) {\n\t\t\t\tr := require.New(t)\n\t\t\t\tr.NotContains(outString, \"help, h  Shows a list of commands or help for one command\")\n\t\t\t\tr.Contains(outString, \"--help, -h  show help\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"with Subcommand\",\n\t\t\targs: []string{\"app\", \"cmd\", \"help\"},\n\t\t\tverify: func(t *testing.T, outString string) {\n\t\t\t\tr := require.New(t)\n\t\t\t\tr.Contains(outString, \"--help, -h  show help\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"without Subcommand\",\n\t\t\targs: []string{\"app\", \"help\"},\n\t\t\tverify: func(t *testing.T, outString string) {\n\t\t\t\tr := require.New(t)\n\t\t\t\tr.Contains(outString, \"help, h  Shows a list of commands or help for one command\")\n\t\t\t\tr.Contains(outString, \"--help, -h  show help\")\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tc := range testCases {\n\t\tout := &bytes.Buffer{}\n\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tcmd := &Command{\n\t\t\t\tName:            \"app\",\n\t\t\t\tHideHelp:        tc.hideHelp,\n\t\t\t\tHideHelpCommand: tc.hideHelpCommand,\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:            \"cmd\",\n\t\t\t\t\t\tHideHelp:        tc.hideHelp,\n\t\t\t\t\t\tHideHelpCommand: tc.hideHelpCommand,\n\t\t\t\t\t\tCommands:        []*Command{{Name: \"subcmd\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tWriter:    out,\n\t\t\t\tErrWriter: out,\n\t\t\t}\n\n\t\t\t_ = cmd.Run(buildTestContext(t), tc.args)\n\t\t\ttc.verify(t, out.String())\n\t\t})\n\t}\n}\n\nfunc TestShowCommandHelp_HelpPrinter(t *testing.T) {\n\t/*doublecho := func(text string) string {\n\t\treturn text + \" \" + text\n\t}*/\n\n\ttests := []struct {\n\t\tname         string\n\t\ttemplate     string\n\t\tprinter      HelpPrinterFunc\n\t\tcommand      string\n\t\twantTemplate string\n\t\twantOutput   string\n\t}{\n\t\t{\n\t\t\tname:     \"no-command\",\n\t\t\ttemplate: \"\",\n\t\t\tprinter: func(w io.Writer, _ string, _ interface{}) {\n\t\t\t\tfmt.Fprint(w, \"yo\")\n\t\t\t},\n\t\t\tcommand:      \"\",\n\t\t\twantTemplate: RootCommandHelpTemplate,\n\t\t\twantOutput:   \"yo\",\n\t\t},\n\t\t/*{\n\t\t\tname:     \"standard-command\",\n\t\t\ttemplate: \"\",\n\t\t\tprinter: func(w io.Writer, templ string, data interface{}) {\n\t\t\t\tfmt.Fprint(w, \"yo\")\n\t\t\t},\n\t\t\tcommand:      \"my-command\",\n\t\t\twantTemplate: CommandHelpTemplate,\n\t\t\twantOutput:   \"yo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom-template-command\",\n\t\t\ttemplate: \"{{doublecho .Name}}\",\n\t\t\tprinter: func(w io.Writer, templ string, data interface{}) {\n\t\t\t\t// Pass a custom function to ensure it gets used\n\t\t\t\tfm := map[string]interface{}{\"doublecho\": doublecho}\n\t\t\t\tHelpPrinterCustom(w, templ, data, fm)\n\t\t\t},\n\t\t\tcommand:      \"my-command\",\n\t\t\twantTemplate: \"{{doublecho .Name}}\",\n\t\t\twantOutput:   \"my-command my-command\",\n\t\t},*/\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdefer func(old HelpPrinterFunc) {\n\t\t\t\tHelpPrinter = old\n\t\t\t}(HelpPrinter)\n\t\t\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\t\t\tassert.Equal(t, tt.wantTemplate, templ, \"template mismatch\")\n\t\t\t\ttt.printer(w, templ, data)\n\t\t\t}\n\n\t\t\tvar buf bytes.Buffer\n\t\t\tcmd := &Command{\n\t\t\t\tName:   \"my-app\",\n\t\t\t\tWriter: &buf,\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:               \"my-command\",\n\t\t\t\t\t\tCustomHelpTemplate: tt.template,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), []string{\"my-app\", \"help\", tt.command})\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgot := buf.String()\n\t\t\tassert.Equal(t, tt.wantOutput, got)\n\t\t})\n\t}\n}\n\nfunc TestShowCommandHelp_HelpPrinterCustom(t *testing.T) {\n\tdoublecho := func(text string) string {\n\t\treturn text + \" \" + text\n\t}\n\n\ttestCases := []struct {\n\t\tname         string\n\t\ttemplate     string\n\t\tprinter      HelpPrinterCustomFunc\n\t\targuments    []string\n\t\twantTemplate string\n\t\twantOutput   string\n\t}{\n\t\t{\n\t\t\tname: \"no command\",\n\t\t\tprinter: func(w io.Writer, _ string, _ any, _ map[string]any) {\n\t\t\t\tfmt.Fprint(w, \"yo\")\n\t\t\t},\n\t\t\targuments:    []string{\"my-app\", \"help\"},\n\t\t\twantTemplate: RootCommandHelpTemplate,\n\t\t\twantOutput:   \"yo\",\n\t\t},\n\t\t{\n\t\t\tname: \"standard command\",\n\t\t\tprinter: func(w io.Writer, _ string, _ any, _ map[string]any) {\n\t\t\t\tfmt.Fprint(w, \"yo\")\n\t\t\t},\n\t\t\targuments:    []string{\"my-app\", \"help\", \"my-command\"},\n\t\t\twantTemplate: SubcommandHelpTemplate,\n\t\t\twantOutput:   \"yo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom template command\",\n\t\t\ttemplate: \"{{doublecho .Name}}\",\n\t\t\tprinter: func(w io.Writer, templ string, data any, _ map[string]any) {\n\t\t\t\t// Pass a custom function to ensure it gets used\n\t\t\t\tfm := map[string]any{\"doublecho\": doublecho}\n\t\t\t\tDefaultPrintHelpCustom(w, templ, data, fm)\n\t\t\t},\n\t\t\targuments:    []string{\"my-app\", \"help\", \"my-command\"},\n\t\t\twantTemplate: \"{{doublecho .Name}}\",\n\t\t\twantOutput:   \"my-command my-command\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tr := require.New(t)\n\n\t\t\tdefer func(old HelpPrinterCustomFunc) {\n\t\t\t\tHelpPrinterCustom = old\n\t\t\t}(HelpPrinterCustom)\n\n\t\t\tHelpPrinterCustom = func(w io.Writer, tmpl string, data any, fm map[string]any) {\n\t\t\t\tr.Nil(fm)\n\t\t\t\tr.Equal(tc.wantTemplate, tmpl)\n\n\t\t\t\ttc.printer(w, tmpl, data, fm)\n\t\t\t}\n\n\t\t\tout := &bytes.Buffer{}\n\t\t\tcmd := &Command{\n\t\t\t\tName:   \"my-app\",\n\t\t\t\tWriter: out,\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:               \"my-command\",\n\t\t\t\t\t\tCustomHelpTemplate: tc.template,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tt.Logf(\"cmd.Run(ctx, %+[1]v)\", tc.arguments)\n\n\t\t\tr.NoError(cmd.Run(buildTestContext(t), tc.arguments))\n\t\t\tr.Equal(tc.wantOutput, out.String())\n\t\t})\n\t}\n}\n\nfunc TestShowCommandHelp_CommandAliases(t *testing.T) {\n\tout := &bytes.Buffer{}\n\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:    \"frobbly\",\n\t\t\t\tAliases: []string{\"fr\", \"frob\", \"bork\"},\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tWriter: out,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"help\", \"fr\"})\n\trequire.Contains(t, out.String(), \"frobbly\")\n}\n\nfunc TestShowSubcommandHelp_CommandAliases(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:    \"frobbly\",\n\t\t\t\tAliases: []string{\"fr\", \"frob\", \"bork\"},\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"help\"})\n\n\tassert.Contains(t, output.String(), \"frobbly, fr, frob, bork\", \"expected output to include all command aliases\")\n}\n\nfunc TestShowCommandHelp_Customtemplate(t *testing.T) {\n\tcmd := &Command{\n\t\tName: \"foo\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tCustomHelpTemplate: `NAME:\n   {{.FullName}} - {{.Usage}}\n\nUSAGE:\n   {{.FullName}} [FLAGS] TARGET [TARGET ...]\n\nFLAGS:\n  {{range .VisibleFlags}}{{.}}\n  {{end}}\nEXAMPLES:\n   1. Frobbly runs with this param locally.\n      $ {{.FullName}} wobbly\n`,\n\t\t\t},\n\t\t},\n\t}\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"help\", \"frobbly\"})\n\n\tassert.NotContains(t, output.String(), \"2. Frobbly runs without this param locally.\",\n\t\t\"expected output to exclude \\\"2. Frobbly runs without this param locally.\\\";\")\n\n\tassert.Contains(t, output.String(), \"1. Frobbly runs with this param locally.\",\n\t\t\"expected output to include \\\"1. Frobbly runs with this param locally.\\\"\")\n\n\tassert.Contains(t, output.String(), \"$ foo frobbly wobbly\",\n\t\t\"expected output to include \\\"$ foo frobbly wobbly\\\"\")\n}\n\nfunc TestShowSubcommandHelp_CommandUsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:      \"frobbly\",\n\t\t\t\tUsageText: \"this is usage text\",\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"frobbly\", \"--help\"})\n\n\tassert.Contains(t, output.String(), \"this is usage text\",\n\t\t\"expected output to include usage text\")\n}\n\nfunc TestShowSubcommandHelp_MultiLine_CommandUsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tUsageText: `This is a\nmulti\nline\nUsageText`,\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"frobbly\", \"--help\"})\n\n\texpected := `USAGE:\n   This is a\n   multi\n   line\n   UsageText\n`\n\n\tassert.Contains(t, output.String(), expected,\n\t\t\"expected output to include usage text\")\n}\n\nfunc TestShowSubcommandHelp_GlobalOptions(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName: \"foo\",\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName:  \"bar\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"frobbly\", \"--help\"})\n\n\texpected := `NAME:\n   foo frobbly\n\nUSAGE:\n   foo frobbly [options]\n\nOPTIONS:\n   --bar string  \n   --help, -h    show help\n\nGLOBAL OPTIONS:\n   --foo string  \n`\n\n\tassert.Contains(t, output.String(), expected, \"expected output to include global options\")\n}\n\nfunc TestShowSubcommandHelp_GlobalOptions_HideHelpCommand(t *testing.T) {\n\tcmd := &Command{\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName: \"foo\",\n\t\t\t},\n\t\t},\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:            \"frobbly\",\n\t\t\t\tHideHelpCommand: true,\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\tName:  \"bar\",\n\t\t\t\t\t\tLocal: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"frobbly\", \"--help\"})\n\n\texpected := `NAME:\n   foo frobbly\n\nUSAGE:\n   foo frobbly [options]\n\nOPTIONS:\n   --bar string  \n   --help, -h    show help\n\nGLOBAL OPTIONS:\n   --foo string  \n`\n\n\tassert.Contains(t, output.String(), expected, \"expected output to include global options\")\n}\n\nfunc TestShowSubcommandHelp_SubcommandUsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      \"bobbly\",\n\t\t\t\t\t\tUsageText: \"this is usage text\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"frobbly\", \"bobbly\", \"--help\"})\n\n\tassert.Contains(t, output.String(), \"this is usage text\",\n\t\t\"expected output to include usage text\")\n}\n\nfunc TestShowSubcommandHelp_MultiLine_SubcommandUsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"bobbly\",\n\t\t\t\t\t\tUsageText: `This is a\nmulti\nline\nUsageText`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"frobbly\", \"bobbly\", \"--help\"})\n\n\texpected := `USAGE:\n   This is a\n   multi\n   line\n   UsageText\n`\n\n\tassert.Contains(t, output.String(), expected,\n\t\t\"expected output to include usage text\")\n}\n\nfunc TestShowRootCommandHelp_HiddenCommand(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"secretfrob\",\n\t\t\t\tHidden: true,\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"app\", \"--help\"})\n\n\tassert.NotContains(t, output.String(), \"secretfrob\",\n\t\t\"expected output to exclude \\\"secretfrob\\\"\")\n\n\tassert.Contains(t, output.String(), \"frobbly\",\n\t\t\"expected output to include \\\"frobbly\\\"\")\n}\n\nfunc TestShowRootCommandHelp_HelpPrinter(t *testing.T) {\n\tdoublecho := func(text string) string {\n\t\treturn text + \" \" + text\n\t}\n\n\ttests := []struct {\n\t\tname         string\n\t\ttemplate     string\n\t\tprinter      HelpPrinterFunc\n\t\twantTemplate string\n\t\twantOutput   string\n\t}{\n\t\t{\n\t\t\tname:     \"standard-command\",\n\t\t\ttemplate: \"\",\n\t\t\tprinter: func(w io.Writer, _ string, _ interface{}) {\n\t\t\t\tfmt.Fprint(w, \"yo\")\n\t\t\t},\n\t\t\twantTemplate: RootCommandHelpTemplate,\n\t\t\twantOutput:   \"yo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom-template-command\",\n\t\t\ttemplate: \"{{doublecho .Name}}\",\n\t\t\tprinter: func(w io.Writer, templ string, data interface{}) {\n\t\t\t\t// Pass a custom function to ensure it gets used\n\t\t\t\tfm := map[string]any{\"doublecho\": doublecho}\n\t\t\t\tDefaultPrintHelpCustom(w, templ, data, fm)\n\t\t\t},\n\t\t\twantTemplate: \"{{doublecho .Name}}\",\n\t\t\twantOutput:   \"my-app my-app\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdefer func(old HelpPrinterFunc) {\n\t\t\t\tHelpPrinter = old\n\t\t\t}(HelpPrinter)\n\t\t\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\t\t\tassert.Equal(t, tt.wantTemplate, templ, \"unexpected template\")\n\t\t\t\ttt.printer(w, templ, data)\n\t\t\t}\n\n\t\t\tvar buf bytes.Buffer\n\t\t\tcmd := &Command{\n\t\t\t\tName:                          \"my-app\",\n\t\t\t\tWriter:                        &buf,\n\t\t\t\tCustomRootCommandHelpTemplate: tt.template,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), []string{\"my-app\", \"help\"})\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.wantOutput, buf.String())\n\t\t})\n\t}\n}\n\nfunc TestShowRootCommandHelp_HelpPrinterCustom(t *testing.T) {\n\tdoublecho := func(text string) string {\n\t\treturn text + \" \" + text\n\t}\n\n\ttests := []struct {\n\t\tname         string\n\t\ttemplate     string\n\t\tprinter      HelpPrinterCustomFunc\n\t\twantTemplate string\n\t\twantOutput   string\n\t}{\n\t\t{\n\t\t\tname:     \"standard-command\",\n\t\t\ttemplate: \"\",\n\t\t\tprinter: func(w io.Writer, _ string, _ interface{}, _ map[string]interface{}) {\n\t\t\t\tfmt.Fprint(w, \"yo\")\n\t\t\t},\n\t\t\twantTemplate: RootCommandHelpTemplate,\n\t\t\twantOutput:   \"yo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom-template-command\",\n\t\t\ttemplate: \"{{doublecho .Name}}\",\n\t\t\tprinter: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) {\n\t\t\t\t// Pass a custom function to ensure it gets used\n\t\t\t\tfm := map[string]any{\"doublecho\": doublecho}\n\t\t\t\tDefaultPrintHelpCustom(w, templ, data, fm)\n\t\t\t},\n\t\t\twantTemplate: \"{{doublecho .Name}}\",\n\t\t\twantOutput:   \"my-app my-app\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdefer func(old HelpPrinterCustomFunc) {\n\t\t\t\tHelpPrinterCustom = old\n\t\t\t}(HelpPrinterCustom)\n\t\t\tHelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {\n\t\t\t\tassert.Nil(t, fm, \"unexpected function map passed\")\n\t\t\t\tassert.Equal(t, tt.wantTemplate, templ, \"unexpected template\")\n\t\t\t\ttt.printer(w, templ, data, fm)\n\t\t\t}\n\n\t\t\tvar buf bytes.Buffer\n\t\t\tcmd := &Command{\n\t\t\t\tName:                          \"my-app\",\n\t\t\t\tWriter:                        &buf,\n\t\t\t\tCustomRootCommandHelpTemplate: tt.template,\n\t\t\t}\n\n\t\t\terr := cmd.Run(buildTestContext(t), []string{\"my-app\", \"help\"})\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.wantOutput, buf.String())\n\t\t})\n\t}\n}\n\nfunc TestShowRootCommandHelp_CustomAppTemplate(t *testing.T) {\n\tcmd := &Command{\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"secretfrob\",\n\t\t\t\tHidden: true,\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tExtraInfo: func() map[string]string {\n\t\t\tplatform := fmt.Sprintf(\"OS: %s | Arch: %s\", runtime.GOOS, runtime.GOARCH)\n\t\t\tgoruntime := fmt.Sprintf(\"Version: %s | CPUs: %d\", runtime.Version(), runtime.NumCPU())\n\t\t\treturn map[string]string{\n\t\t\t\t\"PLATFORM\": platform,\n\t\t\t\t\"RUNTIME\":  goruntime,\n\t\t\t}\n\t\t},\n\t\tCustomRootCommandHelpTemplate: `NAME:\n  {{.Name}} - {{.Usage}}\n\nUSAGE:\n  {{.Name}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}} [COMMAND FLAGS | -h]{{end}} [ARGUMENTS...]\n\nCOMMANDS:\n  {{range .VisibleCommands}}{{join .Names \", \"}}{{ \"\\t\" }}{{.Usage}}\n  {{end}}{{if .VisibleFlags}}\nGLOBAL FLAGS:\n  {{range .VisibleFlags}}{{.}}\n  {{end}}{{end}}\nVERSION:\n  2.0.0\n{{\"\\n\"}}{{range $key, $value := ExtraInfo}}\n{{$key}}:\n  {{$value}}\n{{end}}`,\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"app\", \"--help\"})\n\n\tassert.NotContains(t, output.String(), \"secretfrob\", \"expected output to exclude \\\"secretfrob\\\"\")\n\tassert.Contains(t, output.String(), \"frobbly\", \"expected output to include \\\"frobbly\\\"\")\n\n\tif !strings.Contains(output.String(), \"PLATFORM:\") ||\n\t\t!strings.Contains(output.String(), \"OS:\") ||\n\t\t!strings.Contains(output.String(), \"Arch:\") {\n\t\tt.Errorf(\"expected output to include \\\"PLATFORM:, OS: and Arch:\\\"; got: %q\", output.String())\n\t}\n\n\tif !strings.Contains(output.String(), \"RUNTIME:\") ||\n\t\t!strings.Contains(output.String(), \"Version:\") ||\n\t\t!strings.Contains(output.String(), \"CPUs:\") {\n\t\tt.Errorf(\"expected output to include \\\"RUNTIME:, Version: and CPUs:\\\"; got: %q\", output.String())\n\t}\n\n\tif !strings.Contains(output.String(), \"VERSION:\") ||\n\t\t!strings.Contains(output.String(), \"2.0.0\") {\n\t\tt.Errorf(\"expected output to include \\\"VERSION:, 2.0.0\\\"; got: %q\", output.String())\n\t}\n}\n\nfunc TestShowRootCommandHelp_UsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tUsageText: \"This is a single line of UsageText\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\"})\n\n\tassert.Contains(t, output.String(), \"This is a single line of UsageText\", \"expected output to include usage text\")\n}\n\nfunc TestShowRootCommandHelp_MultiLine_UsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tUsageText: `This is a\nmulti\nline\nApp UsageText`,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"frobbly\",\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\"})\n\n\texpected := `USAGE:\n   This is a\n   multi\n   line\n   App UsageText\n`\n\n\tassert.Contains(t, output.String(), expected, \"expected output to include usage text\")\n}\n\nfunc TestShowRootCommandHelp_CommandMultiLine_UsageText(t *testing.T) {\n\tcmd := &Command{\n\t\tUsageText: `This is a\nmulti\nline\nApp UsageText`,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:    \"frobbly\",\n\t\t\t\tAliases: []string{\"frb1\", \"frbb2\", \"frl2\"},\n\t\t\t\tUsage:   \"this is a long help output for the run command, long usage \\noutput, long usage output, long usage output, long usage output\\noutput, long usage output, long usage output\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"grobbly\",\n\t\t\t\tAliases: []string{\"grb1\", \"grbb2\"},\n\t\t\t\tUsage:   \"this is another long help output for the run command, long usage \\noutput, long usage output\",\n\t\t\t},\n\t\t},\n\t}\n\n\toutput := &bytes.Buffer{}\n\tcmd.Writer = output\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\"})\n\n\texpected := \"COMMANDS:\\n\" +\n\t\t\"   frobbly, frb1, frbb2, frl2  this is a long help output for the run command, long usage \\n\" +\n\t\t\"                               output, long usage output, long usage output, long usage output\\n\" +\n\t\t\"                               output, long usage output, long usage output\\n\" +\n\t\t\"   grobbly, grb1, grbb2        this is another long help output for the run command, long usage \\n\" +\n\t\t\"                               output, long usage output\"\n\tassert.Contains(t, output.String(), expected, \"expected output to include usage text\")\n}\n\nfunc TestHideHelpCommand(t *testing.T) {\n\tcmd := &Command{\n\t\tHideHelpCommand: true,\n\t\tWriter:          io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"help\"})\n\trequire.ErrorContains(t, err, \"No help topic for 'help'\")\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"--help\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestHideHelpCommand_False(t *testing.T) {\n\tcmd := &Command{\n\t\tHideHelpCommand: false,\n\t\tWriter:          io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"help\"})\n\tassert.NoError(t, err)\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"--help\"})\n\tassert.NoError(t, err)\n}\n\nfunc TestHideHelpCommand_WithHideHelp(t *testing.T) {\n\tcmd := &Command{\n\t\tHideHelp:        true, // effective (hides both command and flag)\n\t\tHideHelpCommand: true, // ignored\n\t\tWriter:          io.Discard,\n\t}\n\n\terr := cmd.Run(buildTestContext(t), []string{\"foo\", \"help\"})\n\trequire.ErrorContains(t, err, \"No help topic for 'help'\")\n\n\terr = cmd.Run(buildTestContext(t), []string{\"foo\", \"--help\"})\n\trequire.ErrorContains(t, err, providedButNotDefinedErrMsg)\n}\n\nfunc TestHideHelpCommand_WithSubcommands(t *testing.T) {\n\tcmd := &Command{\n\t\tHideHelpCommand: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"nully\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"nully2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tr := require.New(t)\n\n\tr.ErrorContains(cmd.Run(buildTestContext(t), []string{\"cli.test\", \"help\"}), \"No help topic for 'help'\")\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"cli.test\", \"--help\"}))\n}\n\nfunc TestDefaultCompleteWithFlags(t *testing.T) {\n\torigArgv := os.Args\n\tt.Cleanup(func() { os.Args = origArgv })\n\n\tfor _, tc := range []struct {\n\t\tname     string\n\t\tcmd      *Command\n\t\targv     []string\n\t\tenv      map[string]string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tcmd:      &Command{},\n\t\t\targv:     []string{\"prog\", \"cmd\"},\n\t\t\tenv:      map[string]string{\"SHELL\": \"bash\"},\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"typical-flag-suggestion\",\n\t\t\tcmd: &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\"},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t{Name: \"putz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", \"--e\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"bash\"},\n\t\t\texpected: \"--excitement\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"typical-flag-suggestion-hidden-bool\",\n\t\t\tcmd: &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\", Hidden: true},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t{Name: \"putz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", \"--e\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"bash\"},\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"flag-suggestion-end-args\",\n\t\t\tcmd: &Command{\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\"},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t\tCommands: []*Command{\n\t\t\t\t\t\t{Name: \"putz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", \"--e\", \"--\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"bash\"},\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"typical-command-suggestion\",\n\t\t\tcmd: &Command{\n\t\t\t\tName: \"putz\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{Name: \"futz\"},\n\t\t\t\t},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\"},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"bash\"},\n\t\t\texpected: \"futz\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"autocomplete-with-spaces\",\n\t\t\tcmd: &Command{\n\t\t\t\tName: \"putz\",\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{Name: \"help\"},\n\t\t\t\t},\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\"},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", \"--url\", \"http://localhost:8000\", \"h\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"bash\"},\n\t\t\texpected: \"help\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"zsh-autocomplete-with-flag-descriptions\",\n\t\t\tcmd: &Command{\n\t\t\t\tName: \"putz\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\", Usage: \"an exciting flag\"},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", \"putz\", \"-e\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"zsh\"},\n\t\t\texpected: \"--excitement:an exciting flag\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"zsh-autocomplete-with-empty-flag-descriptions\",\n\t\t\tcmd: &Command{\n\t\t\t\tName: \"putz\",\n\t\t\t\tFlags: []Flag{\n\t\t\t\t\t&BoolFlag{Name: \"excitement\"},\n\t\t\t\t\t&StringFlag{Name: \"hat-shape\"},\n\t\t\t\t},\n\t\t\t\tparent: &Command{\n\t\t\t\t\tName: \"cmd\",\n\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t&BoolFlag{Name: \"happiness\"},\n\t\t\t\t\t\t&Int64Flag{Name: \"everybody-jump-on\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\targv:     []string{\"cmd\", \"putz\", \"-e\", completionFlag},\n\t\t\tenv:      map[string]string{\"SHELL\": \"zsh\"},\n\t\t\texpected: \"--excitement\\n\",\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(ct *testing.T) {\n\t\t\twriter := &bytes.Buffer{}\n\t\t\trootCmd := tc.cmd.Root()\n\t\t\trootCmd.Writer = writer\n\n\t\t\tos.Args = tc.argv\n\t\t\tfor k, v := range tc.env {\n\t\t\t\tct.Setenv(k, v)\n\t\t\t}\n\t\t\ttc.cmd.parsedArgs = &stringSliceArgs{\n\t\t\t\ttc.argv[1:],\n\t\t\t}\n\t\t\tf := DefaultCompleteWithFlags\n\t\t\tf(buildTestContext(ct), tc.cmd)\n\n\t\t\twritten := writer.String()\n\n\t\t\tassert.Equal(ct, tc.expected, written, \"written help does not match\")\n\t\t})\n\t}\n}\n\nfunc TestMutuallyExclusiveFlags(t *testing.T) {\n\twriter := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tName:   \"cmd\",\n\t\tWriter: writer,\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName: \"s1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t_ = ShowRootCommandHelp(cmd)\n\n\tassert.Contains(t, writer.String(), \"--s1\", \"written help does not include mutex flag\")\n}\n\nfunc TestWrap(t *testing.T) {\n\temptywrap := wrap(\"\", 4, 16)\n\tassert.Empty(t, emptywrap, \"Wrapping empty line should return empty line\")\n}\n\nfunc TestWrappedHelp(t *testing.T) {\n\t// Reset HelpPrinter after this test.\n\tdefer func(old HelpPrinterFunc) {\n\t\tHelpPrinter = old\n\t}(HelpPrinter)\n\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{\n\t\tWriter: output,\n\t\tFlags: []Flag{\n\t\t\t&BoolFlag{\n\t\t\t\tName:    \"foo\",\n\t\t\t\tAliases: []string{\"h\"},\n\t\t\t\tUsage:   \"here's a really long help text line, let's see where it wraps. blah blah blah and so on.\",\n\t\t\t},\n\t\t},\n\t\tUsage:     \"here's a sample App.Usage string long enough that it should be wrapped in this test\",\n\t\tUsageText: \"i'm not sure how App.UsageText differs from App.Usage, but this should also be wrapped in this test\",\n\t\t// TODO: figure out how to make ArgsUsage appear in the help text, and test that\n\t\tDescription: `here's a sample App.Description string long enough that it should be wrapped in this test\n\nwith a newline\n   and an indented line`,\n\t\tCopyright: `Here's a sample copyright text string long enough that it should be wrapped.\nIncluding newlines.\n   And also indented lines.\n\n\nAnd then another long line. Blah blah blah does anybody ever read these things?`,\n\t}\n\n\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfuncMap := map[string]interface{}{\n\t\t\t\"wrapAt\": func() int {\n\t\t\t\treturn 30\n\t\t\t},\n\t\t}\n\n\t\tHelpPrinterCustom(w, templ, data, funcMap)\n\t}\n\n\t_ = ShowRootCommandHelp(cmd)\n\n\texpected := `NAME:\n    - here's a sample\n      App.Usage string long\n      enough that it should be\n      wrapped in this test\n\nUSAGE:\n   i'm not sure how\n   App.UsageText differs from\n   App.Usage, but this should\n   also be wrapped in this\n   test\n\nDESCRIPTION:\n   here's a sample\n   App.Description string long\n   enough that it should be\n   wrapped in this test\n\n   with a newline\n      and an indented line\n\nGLOBAL OPTIONS:\n   --foo, -h here's a\n      really long help text\n      line, let's see where it\n      wraps. blah blah blah\n      and so on.\n\nCOPYRIGHT:\n   Here's a sample copyright\n   text string long enough\n   that it should be wrapped.\n   Including newlines.\n      And also indented lines.\n\n\n   And then another long line.\n   Blah blah blah does anybody\n   ever read these things?\n`\n\n\tassert.Equal(t, expected, output.String(), \"Unexpected wrapping\")\n}\n\nfunc TestWrappedCommandHelp(t *testing.T) {\n\t// Reset HelpPrinter after this test.\n\tdefer func(old HelpPrinterFunc) {\n\t\tHelpPrinter = old\n\t}(HelpPrinter)\n\n\toutput := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tWriter:    output,\n\t\tErrWriter: output,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:        \"add\",\n\t\t\t\tAliases:     []string{\"a\"},\n\t\t\t\tUsage:       \"add a task to the list\",\n\t\t\t\tUsageText:   \"this is an even longer way of describing adding a task to the list\",\n\t\t\t\tDescription: \"and a description long enough to wrap in this test case\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tcmd.setupDefaults([]string{\"cli.test\"})\n\tcmd.setupCommandGraph()\n\n\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfuncMap := map[string]interface{}{\n\t\t\t\"wrapAt\": func() int {\n\t\t\t\treturn 30\n\t\t\t},\n\t\t}\n\n\t\tHelpPrinterCustom(w, templ, data, funcMap)\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(ShowCommandHelp(context.Background(), cmd, \"add\"))\n\tr.Equal(`NAME:\n   cli.test add - add a task\n                  to the list\n\nUSAGE:\n   this is an even longer way\n   of describing adding a task\n   to the list\n\nDESCRIPTION:\n   and a description long\n   enough to wrap in this test\n   case\n\nOPTIONS:\n   --help, -h  show help\n`,\n\t\toutput.String(),\n\t)\n}\n\nfunc TestWrappedSubcommandHelp(t *testing.T) {\n\t// Reset HelpPrinter after this test.\n\tdefer func(old HelpPrinterFunc) {\n\t\tHelpPrinter = old\n\t}(HelpPrinter)\n\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{\n\t\tName:   \"cli.test\",\n\t\tWriter: output,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:        \"bar\",\n\t\t\t\tAliases:     []string{\"a\"},\n\t\t\t\tUsage:       \"add a task to the list\",\n\t\t\t\tUsageText:   \"this is an even longer way of describing adding a task to the list\",\n\t\t\t\tDescription: \"and a description long enough to wrap in this test case\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      \"grok\",\n\t\t\t\t\t\tUsage:     \"remove an existing template\",\n\t\t\t\t\t\tUsageText: \"longer usage text goes here, la la la, hopefully this is long enough to wrap even more\",\n\t\t\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfuncMap := map[string]interface{}{\n\t\t\t\"wrapAt\": func() int {\n\t\t\t\treturn 30\n\t\t\t},\n\t\t}\n\n\t\tHelpPrinterCustom(w, templ, data, funcMap)\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"foo\", \"bar\", \"grok\", \"--help\"})\n\n\texpected := `NAME:\n   cli.test bar grok - remove\n                       an\n                       existing\n                       template\n\nUSAGE:\n   longer usage text goes\n   here, la la la, hopefully\n   this is long enough to wrap\n   even more\n\nOPTIONS:\n   --help, -h  show help\n`\n\n\tassert.Equal(t, expected, output.String(), \"Unexpected wrapping\")\n}\n\nfunc TestWrappedHelpSubcommand(t *testing.T) {\n\t// Reset HelpPrinter after this test.\n\tdefer func(old HelpPrinterFunc) {\n\t\tHelpPrinter = old\n\t}(HelpPrinter)\n\n\toutput := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tName:      \"cli.test\",\n\t\tWriter:    output,\n\t\tErrWriter: output,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:        \"bar\",\n\t\t\t\tAliases:     []string{\"a\"},\n\t\t\t\tUsage:       \"add a task to the list\",\n\t\t\t\tUsageText:   \"this is an even longer way of describing adding a task to the list\",\n\t\t\t\tDescription: \"and a description long enough to wrap in this test case\",\n\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tCommands: []*Command{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      \"grok\",\n\t\t\t\t\t\tUsage:     \"remove an existing template\",\n\t\t\t\t\t\tUsageText: \"longer usage text goes here, la la la, hopefully this is long enough to wrap even more\",\n\t\t\t\t\t\tAction: func(context.Context, *Command) error {\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t\tFlags: []Flag{\n\t\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\t\tName:  \"test-f\",\n\t\t\t\t\t\t\t\tUsage: \"my test usage\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfuncMap := map[string]interface{}{\n\t\t\t\"wrapAt\": func() int {\n\t\t\t\treturn 30\n\t\t\t},\n\t\t}\n\n\t\tHelpPrinterCustom(w, templ, data, funcMap)\n\t}\n\n\tr := require.New(t)\n\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"cli.test\", \"bar\", \"help\", \"grok\"}))\n\tr.Equal(`NAME:\n   cli.test bar grok - remove\n                       an\n                       existing\n                       template\n\nUSAGE:\n   longer usage text goes\n   here, la la la, hopefully\n   this is long enough to wrap\n   even more\n\nOPTIONS:\n   --test-f string my test\n      usage\n   --help, -h  show help\n`,\n\t\toutput.String(),\n\t)\n}\n\nfunc TestCategorizedHelp(t *testing.T) {\n\t// Reset HelpPrinter after this test.\n\tdefer func(old HelpPrinterFunc) {\n\t\tHelpPrinter = old\n\t}(HelpPrinter)\n\n\toutput := new(bytes.Buffer)\n\tcmd := &Command{\n\t\tName:   \"cli.test\",\n\t\tWriter: output,\n\t\tAction: func(context.Context, *Command) error { return nil },\n\t\tFlags: []Flag{\n\t\t\t&StringFlag{\n\t\t\t\tName: \"strd\", // no category set\n\t\t\t},\n\t\t\t&Int64Flag{\n\t\t\t\tName:     \"intd\",\n\t\t\t\tAliases:  []string{\"altd1\", \"altd2\"},\n\t\t\t\tCategory: \"cat1\",\n\t\t\t},\n\t\t\t&BoolWithInverseFlag{\n\t\t\t\tName: \"bf\",\n\t\t\t\t// Category: \"cat1\",\n\t\t\t},\n\t\t},\n\t\tMutuallyExclusiveFlags: []MutuallyExclusiveFlags{\n\t\t\t{\n\t\t\t\tCategory: \"cat1\",\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName:     \"m1\",\n\t\t\t\t\t\t\tCategory: \"overridden\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tFlags: [][]Flag{\n\t\t\t\t\t{\n\t\t\t\t\t\t&StringFlag{\n\t\t\t\t\t\t\tName:     \"m2\",\n\t\t\t\t\t\t\tCategory: \"ignored\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tHelpPrinter = func(w io.Writer, templ string, data interface{}) {\n\t\tfuncMap := map[string]interface{}{\n\t\t\t\"wrapAt\": func() int {\n\t\t\t\treturn 30\n\t\t\t},\n\t\t}\n\n\t\tHelpPrinterCustom(w, templ, data, funcMap)\n\t}\n\n\tr := require.New(t)\n\tr.NoError(cmd.Run(buildTestContext(t), []string{\"cli.test\", \"help\"}))\n\n\tr.Equal(`NAME:\n   cli.test - A new cli\n              application\n\nUSAGE:\n   cli.test [global options]\n\nGLOBAL OPTIONS:\n   --[no-]bf      (default: false)\n   --help, -h     show help\n   --m2 string    \n   --strd string  \n\n   cat1\n\n   --intd int, --altd1 int, --altd2 int  (default: 0)\n   --m1 string                           \n\n`, output.String())\n}\n\nfunc Test_checkShellCompleteFlag(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tname                string\n\t\tcmd                 *Command\n\t\targuments           []string\n\t\twantShellCompletion bool\n\t\twantArgs            []string\n\t}{\n\t\t{\n\t\t\tname:                \"disable-shell-completion\",\n\t\t\targuments:           []string{completionFlag},\n\t\t\tcmd:                 &Command{},\n\t\t\twantShellCompletion: false,\n\t\t\twantArgs:            []string{completionFlag},\n\t\t},\n\t\t{\n\t\t\tname:      \"child-disable-shell-completion\",\n\t\t\targuments: []string{completionFlag},\n\t\t\tcmd: &Command{\n\t\t\t\tparent: &Command{},\n\t\t\t},\n\t\t\twantShellCompletion: false,\n\t\t\twantArgs:            []string{completionFlag},\n\t\t},\n\t\t{\n\t\t\tname:      \"last argument isn't --generate-shell-completion\",\n\t\t\targuments: []string{\"foo\"},\n\t\t\tcmd: &Command{\n\t\t\t\tEnableShellCompletion: true,\n\t\t\t},\n\t\t\twantShellCompletion: false,\n\t\t\twantArgs:            []string{\"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:      \"arguments include double dash\",\n\t\t\targuments: []string{\"--\", \"foo\", completionFlag},\n\t\t\tcmd: &Command{\n\t\t\t\tEnableShellCompletion: true,\n\t\t\t},\n\t\t\twantShellCompletion: false,\n\t\t\twantArgs:            []string{\"--\", \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:      \"shell completion\",\n\t\t\targuments: []string{\"foo\", completionFlag},\n\t\t\tcmd: &Command{\n\t\t\t\tEnableShellCompletion: true,\n\t\t\t},\n\t\t\twantShellCompletion: true,\n\t\t\twantArgs:            []string{\"foo\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tshellCompletion, args := checkShellCompleteFlag(tt.cmd, tt.arguments)\n\t\t\tassert.Equal(t, tt.wantShellCompletion, shellCompletion)\n\t\t\tassert.Equal(t, tt.wantArgs, args)\n\t\t})\n\t}\n}\n\nfunc TestNIndent(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tnumSpaces int\n\t\tstr       string\n\t\texpected  string\n\t}{\n\t\t{\n\t\t\tnumSpaces: 0,\n\t\t\tstr:       \"foo\",\n\t\t\texpected:  \"\\nfoo\",\n\t\t},\n\t\t{\n\t\t\tnumSpaces: 0,\n\t\t\tstr:       \"foo\\n\",\n\t\t\texpected:  \"\\nfoo\\n\",\n\t\t},\n\t\t{\n\t\t\tnumSpaces: 2,\n\t\t\tstr:       \"foo\",\n\t\t\texpected:  \"\\n  foo\",\n\t\t},\n\t\t{\n\t\t\tnumSpaces: 3,\n\t\t\tstr:       \"foo\\n\",\n\t\t\texpected:  \"\\n   foo\\n   \",\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tassert.Equal(t, test.expected, nindent(test.numSpaces, test.str))\n\t}\n}\n\nfunc TestTemplateError(t *testing.T) {\n\toldew := ErrWriter\n\tdefer func() { ErrWriter = oldew }()\n\n\tvar buf bytes.Buffer\n\tErrWriter = &buf\n\terr := errors.New(\"some error\")\n\n\thandleTemplateError(err)\n\tassert.Equal(t, []byte(nil), buf.Bytes())\n\n\tt.Setenv(\"CLI_TEMPLATE_ERROR_DEBUG\", \"true\")\n\thandleTemplateError(err)\n\tassert.Contains(t, buf.String(), \"CLI TEMPLATE ERROR\")\n\tassert.Contains(t, buf.String(), err.Error())\n}\n\nfunc TestCliArgContainsFlag(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\targs     []string\n\t\tcontains bool\n\t}{\n\t\t{\n\t\t\tname: \"\",\n\t\t\targs: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"f\",\n\t\t\targs: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"f\",\n\t\t\targs: []string{\"g\", \"foo\", \"f\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"f\",\n\t\t\targs:     []string{\"-f\", \"foo\", \"f\"},\n\t\t\tcontains: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"f\",\n\t\t\targs:     []string{\"g\", \"-f\", \"f\"},\n\t\t\tcontains: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"fh\",\n\t\t\targs:     []string{\"g\", \"f\", \"--fh\"},\n\t\t\tcontains: true,\n\t\t},\n\t\t{\n\t\t\tname: \"fhg\",\n\t\t\targs: []string{\"-fhg\", \"f\", \"fh\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"fhg\",\n\t\t\targs:     []string{\"--fhg\", \"f\", \"fh\"},\n\t\t\tcontains: true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tif test.contains {\n\t\t\tassert.True(t, cliArgContains(test.name, test.args))\n\t\t} else {\n\t\t\tassert.False(t, cliArgContains(test.name, test.args))\n\t\t}\n\t}\n}\n\nfunc TestCommandHelpSuggest(t *testing.T) {\n\tcmd := &Command{\n\t\tSuggest: true,\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName: \"putz\",\n\t\t\t},\n\t\t},\n\t}\n\n\tcmd.setupDefaults([]string{\"foo\"})\n\n\terr := ShowCommandHelp(context.Background(), cmd, \"put\")\n\tassert.ErrorContains(t, err, \"No help topic for 'put'. putz\")\n}\n\nfunc TestWrapLine(t *testing.T) {\n\tassert.Equal(t, \"    \", wrapLine(\"    \", 0, 3, \" \"))\n}\n\nfunc TestPrintHelpCustomTemplateError(t *testing.T) {\n\ttmpls := []*string{\n\t\t&helpNameTemplate,\n\t\t&argsTemplate,\n\t\t&usageTemplate,\n\t\t&descriptionTemplate,\n\t\t&visibleCommandTemplate,\n\t\t&copyrightTemplate,\n\t\t&versionTemplate,\n\t\t&visibleFlagCategoryTemplate,\n\t\t&visibleFlagTemplate,\n\t\t&visiblePersistentFlagTemplate,\n\t\t&visibleFlagCategoryTemplate,\n\t\t&authorsTemplate,\n\t\t&visibleCommandCategoryTemplate,\n\t}\n\n\toldErrWriter := ErrWriter\n\tdefer func() { ErrWriter = oldErrWriter }()\n\n\tt.Setenv(\"CLI_TEMPLATE_ERROR_DEBUG\", \"true\")\n\n\tfor _, tmpl := range tmpls {\n\t\toldtmpl := *tmpl\n\t\t// safety mechanism in case something fails\n\t\tdefer func(stmpl *string) { *stmpl = oldtmpl }(tmpl)\n\n\t\terrBuf := &bytes.Buffer{}\n\t\tErrWriter = errBuf\n\t\tbuf := &bytes.Buffer{}\n\n\t\t*tmpl = \"{{junk\"\n\t\tDefaultPrintHelpCustom(buf, \"\", \"\", nil)\n\n\t\tassert.Contains(t, errBuf.String(), \"CLI TEMPLATE ERROR\")\n\n\t\t// reset template back.\n\t\t*tmpl = oldtmpl\n\t}\n}\n\nfunc TestCustomUsageCommandHelp(t *testing.T) {\n\told := UsageCommandHelp\n\tdefer func() { UsageCommandHelp = old }()\n\n\tUsageCommandHelp = \"Custom usage help command\"\n\n\tout := &bytes.Buffer{}\n\tcmd := &Command{\n\t\tName: \"app\",\n\t\tCommands: []*Command{\n\t\t\t{\n\t\t\t\tName:     \"cmd\",\n\t\t\t\tCommands: []*Command{{Name: \"subcmd\"}},\n\t\t\t},\n\t\t},\n\t\tWriter:    out,\n\t\tErrWriter: out,\n\t}\n\n\t_ = cmd.Run(buildTestContext(t), []string{\"app\", \"help\"})\n\tassert.Contains(t, out.String(), UsageCommandHelp)\n}\n"
  },
  {
    "path": "helpers_test.go",
    "content": "package cli\n\nimport (\n\t\"os\"\n)\n\nfunc init() {\n\t_ = os.Setenv(\"CLI_TEMPLATE_REPANIC\", \"1\")\n}\n"
  },
  {
    "path": "mkdocs-requirements.txt",
    "content": "mkdocs-git-revision-date-localized-plugin==1.5.1\nmkdocs-material==9.7.4\nmkdocs==1.6.1\nmkdocs-redirects==1.2.2\npygments==2.19.2\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "# NOTE: the mkdocs dependencies will need to be installed out of\n# band until this whole thing gets more automated:\n#\n#     pip install -r mkdocs-requirements.txt\n#\n\nsite_name: urfave/cli\nsite_url: https://cli.urfave.org/\nrepo_url: https://github.com/urfave/cli\nedit_uri: edit/main/docs/\nnav:\n  - Home:\n      - Welcome: index.md\n      - Contributing: CONTRIBUTING.md\n      - Code of Conduct: CODE_OF_CONDUCT.md\n      - Releasing: RELEASING.md\n      - Security: SECURITY.md\n      - Migrate v2 to v3: migrate-v2-to-v3.md\n      - Migrate v1 to v2: migrate-v1-to-v2.md\n  - v3 Manual:\n      - Getting Started: v3/getting-started.md\n      - Migrating From Older Releases: v3/migrating-from-older-releases.md\n      - Examples:\n          - Greet: v3/examples/greet.md\n          - Flags: \n              - Basics: v3/examples/flags/basics.md\n              - Value Sources: v3/examples/flags/value-sources.md\n              - Short Options: v3/examples/flags/short-options.md\n              - Advanced: v3/examples/flags/advanced.md\n          - Arguments: \n              - Basics: v3/examples/arguments/basics.md\n              - Advanced: v3/examples/arguments/advanced.md\n          - Subcommands: \n              - Basics: v3/examples/subcommands/basics.md\n              - Categories: v3/examples/subcommands/categories.md\n          - Completions:\n              - Shell Completions: v3/examples/completions/shell-completions.md\n              - Customizations: v3/examples/completions/customizations.md\n          - Help Text:\n              - Generated Help Text: v3/examples/help/generated-help-text.md\n              - Suggestions: v3/examples/help/suggestions.md\n          - Error Handling:\n              - Exit Codes: v3/examples/exit-codes.md          \n          - Full API Example: v3/examples/full-api-example.md\n  - v2 Manual:\n      - Getting Started: v2/getting-started.md\n      - Migrating to v3: v2/migrating-to-v3.md\n      - Migrating From Older Releases: v2/migrating-from-older-releases.md\n      - Examples:\n          - Greet: v2/examples/greet.md\n          - Arguments: v2/examples/arguments.md\n          - Flags: v2/examples/flags.md\n          - Subcommands: v2/examples/subcommands.md\n          - Subcommands Categories: v2/examples/subcommands-categories.md\n          - Exit Codes: v2/examples/exit-codes.md\n          - Combining Short Options: v2/examples/combining-short-options.md\n          - Bash Completions: v2/examples/bash-completions.md\n          - Generated Help Text: v2/examples/generated-help-text.md\n          - Version Flag: v2/examples/version-flag.md\n          - Timestamp Flag: v2/examples/timestamp-flag.md\n          - Suggestions: v2/examples/suggestions.md\n          - Full API Example: v2/examples/full-api-example.md\n  - v1 Manual:\n      - Getting Started: v1/getting-started.md\n      - Migrating to v2: v1/migrating-to-v2.md\n      - Examples:\n          - Greet: v1/examples/greet.md\n          - Arguments: v1/examples/arguments.md\n          - Flags: v1/examples/flags.md\n          - Subcommands: v1/examples/subcommands.md\n          - Subcommands (Categories): v1/examples/subcommands-categories.md\n          - Exit Codes: v1/examples/exit-codes.md\n          - Combining Short Options: v1/examples/combining-short-options.md\n          - Bash Completions: v1/examples/bash-completions.md\n          - Generated Help Text: v1/examples/generated-help-text.md\n          - Version Flag: v1/examples/version-flag.md\n\ntheme:\n  name: material\n  palette:\n    - media: \"(prefers-color-scheme: light)\"\n      scheme: default\n      toggle:\n        icon: material/brightness-4\n        name: dark mode\n    - media: \"(prefers-color-scheme: dark)\"\n      scheme: slate\n      toggle:\n        icon: material/brightness-7\n        name: light mode\n  features:\n    - content.code.annotate\n    - navigation.top\n    - navigation.instant\n    - navigation.expand\n    - navigation.sections\n    - navigation.tabs\n    - navigation.tabs.sticky\n\nplugins:\n  - git-revision-date-localized\n  - search\n  - redirects:\n      redirect_maps:\n        'v3/examples/bash-completions.md': 'v3/examples/completions/shell-completions.md'\n  - tags\n\n# NOTE: this is the recommended configuration from\n# https://squidfunk.github.io/mkdocs-material/setup/extensions/#recommended-configuration\nmarkdown_extensions:\n  - abbr\n  - admonition\n  - attr_list\n  - def_list\n  - footnotes\n  - meta\n  - md_in_html\n  - toc:\n      permalink: true\n  - pymdownx.arithmatex:\n      generic: true\n  - pymdownx.betterem:\n      smart_enable: all\n  - pymdownx.caret\n  - pymdownx.details\n  - pymdownx.emoji:\n      emoji_index: !!python/name:material.extensions.emoji.twemoji\n      emoji_generator: !!python/name:material.extensions.emoji.to_svg\n  - pymdownx.highlight\n  - pymdownx.inlinehilite\n  - pymdownx.keys\n  - pymdownx.mark\n  - pymdownx.smartsymbols\n  - pymdownx.superfences\n  - pymdownx.tabbed:\n      alternate_style: true\n  - pymdownx.tasklist:\n      custom_checkbox: true\n  - pymdownx.tilde\n"
  },
  {
    "path": "scripts/build.go",
    "content": "// local build script file, similar to a makefile or collection of bash scripts in other projects\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nconst (\n\tbadNewsEmoji      = \"🚨\"\n\tgoodNewsEmoji     = \"✨\"\n\tchecksPassedEmoji = \"✅\"\n\n\tgfmrunVersion = \"v1.3.0\"\n\n\tv3diffWarning = `\n# The unified diff above indicates that the public API surface area\n# has changed. If you feel that the changes are acceptable for the\n# v3.x series, please run the following command to promote the\n# current go docs:\n#\n#     make v3approve\n#\n`\n)\n\nfunc main() {\n\ttopDir, err := func() (string, error) {\n\t\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\t\tdefer cancel()\n\n\t\tif v, err := sh(ctx, \"git\", \"rev-parse\", \"--show-toplevel\"); err == nil {\n\t\t\treturn strings.TrimSpace(v), nil\n\t\t}\n\n\t\treturn os.Getwd()\n\t}()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tapp := &cli.Command{\n\t\tName:  \"builder\",\n\t\tUsage: \"Do a thing for urfave/cli! (maybe build?)\",\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:   \"vet\",\n\t\t\t\tAction: topRunAction(\"go\", \"vet\", \"./...\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"test\",\n\t\t\t\tAction: TestActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"gfmrun\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\tName:  \"walk\",\n\t\t\t\t\t\tValue: false,\n\t\t\t\t\t\tUsage: \"Walk the specified directory and perform validation on all markdown files\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: GfmrunActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"check-binary-size\",\n\t\t\t\tAction: checkBinarySizeActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"generate\",\n\t\t\t\tAction: GenerateActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"diffcheck\",\n\t\t\t\tAction: DiffCheckActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"ensure-goimports\",\n\t\t\t\tAction: EnsureGoimportsActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"ensure-gfmrun\",\n\t\t\t\tAction: EnsureGfmrunActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"ensure-mkdocs\",\n\t\t\t\tAction: EnsureMkdocsActionFunc,\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"upgrade-pip\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"set-mkdocs-remote\",\n\t\t\t\tAction: SetMkdocsRemoteActionFunc,\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\tName:     \"github-token\",\n\t\t\t\t\t\tSources:  cli.EnvVars(\"MKDOCS_REMOTE_GITHUB_TOKEN\"),\n\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"deploy-mkdocs\",\n\t\t\t\tAction: topRunAction(\"mkdocs\", \"gh-deploy\", \"--force\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"lint\",\n\t\t\t\tAction: LintActionFunc,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"v3diff\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{Name: \"color\", Value: false},\n\t\t\t\t},\n\t\t\t\tAction: V3Diff,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"v3approve\",\n\t\t\t\tAction: topRunAction(\n\t\t\t\t\t\"cp\",\n\t\t\t\t\t\"-v\",\n\t\t\t\t\t\"godoc-current.txt\",\n\t\t\t\t\tfilepath.Join(\"testdata\", \"godoc-v3.x.txt\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:  \"tags\",\n\t\t\t\tUsage: \"set build tags\",\n\t\t\t},\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:  \"top-dir\",\n\t\t\t\tValue: topDir,\n\t\t\t},\n\t\t\t&cli.StringSliceFlag{\n\t\t\t\tName:  \"packages\",\n\t\t\t\tValue: []string{\"cli\", \"scripts\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc sh(ctx context.Context, exe string, args ...string) (string, error) {\n\tcmd := exec.CommandContext(ctx, exe, args...)\n\tcmd.Stdin = os.Stdin\n\tcmd.Stderr = os.Stderr\n\n\tfmt.Fprintf(os.Stderr, \"# ---> %s\\n\", cmd)\n\toutBytes, err := cmd.Output()\n\treturn string(outBytes), err\n}\n\nfunc topRunAction(arg string, args ...string) cli.ActionFunc {\n\treturn func(ctx context.Context, cmd *cli.Command) error {\n\t\tif err := os.Chdir(cmd.String(\"top-dir\")); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn runCmd(ctx, arg, args...)\n\t}\n}\n\nfunc runCmd(ctx context.Context, arg string, args ...string) error {\n\tcmd := exec.CommandContext(ctx, arg, args...)\n\n\tcmd.Stdin = os.Stdin\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\tfmt.Fprintf(os.Stderr, \"# ---> %s\\n\", cmd)\n\treturn cmd.Run()\n}\n\nfunc downloadFile(src, dest string, dirPerm, perm os.FileMode) error {\n\treq, err := http.NewRequest(http.MethodGet, src, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode >= 300 {\n\t\treturn fmt.Errorf(\"download file from %[2]s into %[3]s: response %[1]v\", resp.StatusCode, src, dest)\n\t}\n\n\tif err := os.MkdirAll(filepath.Dir(dest), dirPerm); err != nil {\n\t\treturn err\n\t}\n\n\tout, err := os.Create(dest)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := io.Copy(out, resp.Body); err != nil {\n\t\treturn err\n\t}\n\n\tif err := out.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.Chmod(dest, perm)\n}\n\nfunc VetActionFunc(ctx context.Context, cmd *cli.Command) error {\n\treturn runCmd(ctx, \"go\", \"vet\", cmd.String(\"top-dir\")+\"/...\")\n}\n\nfunc TestActionFunc(ctx context.Context, cmd *cli.Command) error {\n\ttags := cmd.String(\"tags\")\n\n\tfor _, pkg := range cmd.StringSlice(\"packages\") {\n\t\tpackageName := \"github.com/urfave/cli/v3\"\n\n\t\tif pkg != \"cli\" {\n\t\t\tpackageName = fmt.Sprintf(\"github.com/urfave/cli/v3/%s\", pkg)\n\t\t}\n\n\t\targs := []string{\"test\"}\n\t\tif tags != \"\" {\n\t\t\targs = append(args, []string{\"-tags\", tags}...)\n\t\t}\n\n\t\targs = append(args, []string{\n\t\t\t\"-v\",\n\t\t\t\"-race\",\n\t\t\t\"--coverprofile\", pkg + \".coverprofile\",\n\t\t\t\"--covermode\", \"atomic\",\n\t\t\t\"--cover\", packageName,\n\t\t\tpackageName,\n\t\t}...)\n\n\t\tif err := runCmd(ctx, \"go\", args...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn testCleanup(cmd.StringSlice(\"packages\"))\n}\n\nfunc testCleanup(packages []string) error {\n\tout := &bytes.Buffer{}\n\n\tfmt.Fprintf(out, \"mode: count\\n\")\n\n\tfor _, pkg := range packages {\n\t\tfilename := pkg + \".coverprofile\"\n\n\t\tlineBytes, err := os.ReadFile(filename)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlines := strings.Split(string(lineBytes), \"\\n\")\n\n\t\tfmt.Fprint(out, strings.Join(lines[1:], \"\\n\"))\n\n\t\tif err := os.Remove(filename); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn os.WriteFile(\"coverage.txt\", out.Bytes(), 0o644)\n}\n\nfunc GfmrunActionFunc(ctx context.Context, cmd *cli.Command) error {\n\tdocsDir := filepath.Join(cmd.String(\"top-dir\"), \"docs\")\n\n\tbash, err := exec.LookPath(\"bash\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tos.Setenv(\"SHELL\", bash)\n\n\ttmpDir, err := os.MkdirTemp(\"\", \"urfave-cli*\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\twd, err := os.Getwd()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.Chdir(tmpDir); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintf(cmd.ErrWriter, \"# ---> workspace/TMPDIR is %q\\n\", tmpDir)\n\n\tif err := runCmd(ctx, \"go\", \"work\", \"init\", docsDir); err != nil {\n\t\treturn err\n\t}\n\n\tos.Setenv(\"TMPDIR\", tmpDir)\n\n\tif err := os.Chdir(wd); err != nil {\n\t\treturn err\n\t}\n\n\tdirPath := cmd.Args().Get(0)\n\tif dirPath == \"\" {\n\t\tdirPath = \"README.md\"\n\t}\n\n\twalk := cmd.Bool(\"walk\")\n\tsources := []string{}\n\n\tif walk {\n\t\t// Walk the directory and find all markdown files.\n\t\terr := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif info.IsDir() {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif filepath.Ext(path) != \".md\" {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tsources = append(sources, path)\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tsources = append(sources, dirPath)\n\t}\n\n\tvar counter int\n\n\tfor _, src := range sources {\n\t\tfile, err := os.Open(src)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer file.Close()\n\n\t\tscanner := bufio.NewScanner(file)\n\t\tfor scanner.Scan() {\n\t\t\tif strings.Contains(scanner.Text(), \"package main\") {\n\t\t\t\tcounter++\n\t\t\t}\n\t\t}\n\n\t\terr = file.Close()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = scanner.Err()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tgfmArgs := []string{\n\t\t\"--count\",\n\t\tfmt.Sprint(counter),\n\t}\n\tfor _, src := range sources {\n\t\tgfmArgs = append(gfmArgs, \"--sources\", src)\n\t}\n\n\tif err := runCmd(ctx, \"gfmrun\", gfmArgs...); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.RemoveAll(tmpDir)\n}\n\n// checkBinarySizeActionFunc checks the size of an example binary to ensure that we are keeping size down\n// this was originally inspired by https://github.com/urfave/cli/issues/1055, and followed up on as a part\n// of https://github.com/urfave/cli/issues/1057\nfunc checkBinarySizeActionFunc(ctx context.Context, cmd *cli.Command) (err error) {\n\tconst (\n\t\tcliSourceFilePath    = \"./examples/example-cli/example-cli.go\"\n\t\tcliBuiltFilePath     = \"./examples/example-cli/built-example\"\n\t\thelloSourceFilePath  = \"./examples/example-hello-world/example-hello-world.go\"\n\t\thelloBuiltFilePath   = \"./examples/example-hello-world/built-example\"\n\t\tdesiredMaxBinarySize = 2.2\n\t\tdesiredMinBinarySize = 1.49\n\t\tmbStringFormatter    = \"%.1fMB\"\n\t)\n\n\ttags := cmd.String(\"tags\")\n\n\t// get cli example size\n\tcliSize, err := getSize(ctx, cliSourceFilePath, cliBuiltFilePath, tags)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// get hello world size\n\thelloSize, err := getSize(ctx, helloSourceFilePath, helloBuiltFilePath, tags)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// The CLI size diff is the number we are interested in.\n\t// This tells us how much our CLI package contributes to the binary size.\n\tcliSizeDiff := cliSize - helloSize\n\n\t// get human readable size, in MB with one decimal place.\n\t// example output is: 35.2MB. (note: this simply an example)\n\t// that output is much easier to reason about than the `35223432`\n\t// that you would see output without the rounding\n\tfileSizeInMB := float64(cliSizeDiff) / float64(1000000)\n\troundedFileSize := math.Round(fileSizeInMB*10) / 10\n\troundedFileSizeString := fmt.Sprintf(mbStringFormatter, roundedFileSize)\n\n\t// check against bounds\n\tisLessThanDesiredMin := roundedFileSize < desiredMinBinarySize\n\tisMoreThanDesiredMax := roundedFileSize > desiredMaxBinarySize\n\tdesiredMinSizeString := fmt.Sprintf(mbStringFormatter, desiredMinBinarySize)\n\tdesiredMaxSizeString := fmt.Sprintf(mbStringFormatter, desiredMaxBinarySize)\n\n\t// show guidance\n\tfmt.Printf(\"\\n%s is the current binary size\\n\", roundedFileSizeString)\n\t// show guidance for min size\n\tif isLessThanDesiredMin {\n\t\tfmt.Printf(\"  %s %s is the target min size\\n\", goodNewsEmoji, desiredMinSizeString)\n\t\tfmt.Println(\"\") // visual spacing\n\t\tfmt.Println(\"     The binary is smaller than the target min size, which is great news!\")\n\t\tfmt.Println(\"     That means that your changes are shrinking the binary size.\")\n\t\tfmt.Println(\"     You'll want to go into ./scripts/build.go and decrease\")\n\t\tfmt.Println(\"     the desiredMinBinarySize, and also probably decrease the \")\n\t\tfmt.Println(\"     desiredMaxBinarySize by the same amount. That will ensure that\")\n\t\tfmt.Println(\"     future PRs will enforce the newly shrunk binary sizes.\")\n\t\tfmt.Println(\"\") // visual spacing\n\t\tos.Exit(1)\n\t} else {\n\t\tfmt.Printf(\"  %s %s is the target min size\\n\", checksPassedEmoji, desiredMinSizeString)\n\t}\n\t// show guidance for max size\n\tif isMoreThanDesiredMax {\n\t\tfmt.Printf(\"  %s %s is the target max size\\n\", badNewsEmoji, desiredMaxSizeString)\n\t\tfmt.Println(\"\") // visual spacing\n\t\tfmt.Println(\"     The binary is larger than the target max size.\")\n\t\tfmt.Println(\"     That means that your changes are increasing the binary size.\")\n\t\tfmt.Println(\"     The first thing you'll want to do is ask your yourself\")\n\t\tfmt.Println(\"     Is this change worth increasing the binary size?\")\n\t\tfmt.Println(\"     Larger binary sizes for this package can dissuade its use.\")\n\t\tfmt.Println(\"     If this change is worth the increase, then we can up the\")\n\t\tfmt.Println(\"     desired max binary size. To do that you'll want to go into\")\n\t\tfmt.Println(\"     ./scripts/build.go and increase the desiredMaxBinarySize,\")\n\t\tfmt.Println(\"     and increase the desiredMinBinarySize by the same amount.\")\n\t\tfmt.Println(\"\") // visual spacing\n\t\tos.Exit(1)\n\t} else {\n\t\tfmt.Printf(\"  %s %s is the target max size\\n\", checksPassedEmoji, desiredMaxSizeString)\n\t}\n\n\treturn nil\n}\n\nfunc GenerateActionFunc(ctx context.Context, cmd *cli.Command) error {\n\ttopDir := cmd.String(\"top-dir\")\n\n\tcliDocs, err := sh(ctx, \"go\", \"doc\", \"-all\", topDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(\n\t\tfilepath.Join(topDir, \"godoc-current.txt\"),\n\t\t[]byte(cliDocs),\n\t\t0o644,\n\t)\n}\n\nfunc DiffCheckActionFunc(ctx context.Context, cmd *cli.Command) error {\n\tif err := os.Chdir(cmd.String(\"top-dir\")); err != nil {\n\t\treturn err\n\t}\n\n\tif err := runCmd(ctx, \"git\", \"diff\", \"--exit-code\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn runCmd(ctx, \"git\", \"diff\", \"--cached\", \"--exit-code\")\n}\n\nfunc EnsureGoimportsActionFunc(ctx context.Context, cmd *cli.Command) error {\n\ttopDir := cmd.String(\"top-dir\")\n\tif err := os.Chdir(topDir); err != nil {\n\t\treturn err\n\t}\n\n\tif err := runCmd(\n\t\tctx,\n\t\t\"goimports\",\n\t\t\"-d\",\n\t\tfilepath.Join(topDir, \"scripts/build.go\"),\n\t); err == nil {\n\t\treturn nil\n\t}\n\n\tos.Setenv(\"GOBIN\", filepath.Join(topDir, \".local/bin\"))\n\n\treturn runCmd(ctx, \"go\", \"install\", \"golang.org/x/tools/cmd/goimports@latest\")\n}\n\nfunc EnsureGfmrunActionFunc(ctx context.Context, cmd *cli.Command) error {\n\ttopDir := cmd.String(\"top-dir\")\n\tgfmrunExe := filepath.Join(topDir, \".local/bin/gfmrun\")\n\n\tif err := os.Chdir(topDir); err != nil {\n\t\treturn err\n\t}\n\n\tif v, err := sh(ctx, gfmrunExe, \"--version\"); err == nil && strings.TrimSpace(v) == gfmrunVersion {\n\t\treturn nil\n\t}\n\n\tgfmrunURL, err := url.Parse(\n\t\tfmt.Sprintf(\n\t\t\t\"https://github.com/urfave/gfmrun/releases/download/%[1]s/gfmrun-%[2]s-%[3]s-%[1]s\",\n\t\t\tgfmrunVersion, runtime.GOOS, runtime.GOARCH,\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn downloadFile(gfmrunURL.String(), gfmrunExe, 0o755, 0o755)\n}\n\nfunc EnsureMkdocsActionFunc(ctx context.Context, cmd *cli.Command) error {\n\tif err := os.Chdir(cmd.String(\"top-dir\")); err != nil {\n\t\treturn err\n\t}\n\n\tif err := runCmd(ctx, \"mkdocs\", \"--version\"); err == nil {\n\t\treturn nil\n\t}\n\n\tif cmd.Bool(\"upgrade-pip\") {\n\t\tif err := runCmd(ctx, \"pip\", \"install\", \"-U\", \"pip\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn runCmd(ctx, \"pip\", \"install\", \"-r\", \"mkdocs-requirements.txt\")\n}\n\nfunc SetMkdocsRemoteActionFunc(ctx context.Context, cmd *cli.Command) error {\n\tghToken := strings.TrimSpace(cmd.String(\"github-token\"))\n\tif ghToken == \"\" {\n\t\treturn errors.New(\"empty github token\")\n\t}\n\n\tif err := os.Chdir(cmd.String(\"top-dir\")); err != nil {\n\t\treturn err\n\t}\n\n\tif err := runCmd(ctx, \"git\", \"remote\", \"rm\", \"origin\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn runCmd(\n\t\tctx,\n\t\t\"git\", \"remote\", \"add\", \"origin\",\n\t\tfmt.Sprintf(\"https://x-access-token:%[1]s@github.com/urfave/cli.git\", ghToken),\n\t)\n}\n\nfunc LintActionFunc(ctx context.Context, cmd *cli.Command) error {\n\ttopDir := cmd.String(\"top-dir\")\n\tif err := os.Chdir(topDir); err != nil {\n\t\treturn err\n\t}\n\n\tout, err := sh(ctx, filepath.Join(topDir, \".local/bin/goimports\"), \"-l\", \".\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif strings.TrimSpace(out) != \"\" {\n\t\tfmt.Fprintln(cmd.ErrWriter, \"# ---> goimports -l is non-empty:\")\n\t\tfmt.Fprintln(cmd.ErrWriter, out)\n\n\t\treturn errors.New(\"goimports needed\")\n\t}\n\n\treturn nil\n}\n\nfunc V3Diff(ctx context.Context, cmd *cli.Command) error {\n\tif err := os.Chdir(cmd.String(\"top-dir\")); err != nil {\n\t\treturn err\n\t}\n\n\terr := runCmd(\n\t\tctx,\n\t\t\"diff\",\n\t\t\"--ignore-all-space\",\n\t\t\"--minimal\",\n\t\t\"--color=\"+func() string {\n\t\t\tif cmd.Bool(\"color\") {\n\t\t\t\treturn \"always\"\n\t\t\t}\n\t\t\treturn \"auto\"\n\t\t}(),\n\t\t\"--unified\",\n\t\t\"--label=a/godoc\",\n\t\tfilepath.Join(\"testdata\", \"godoc-v3.x.txt\"),\n\t\t\"--label=b/godoc\",\n\t\t\"godoc-current.txt\",\n\t)\n\tif err != nil {\n\t\tfmt.Printf(\"# %v ---> Hey! <---\\n\", badNewsEmoji)\n\t\tfmt.Println(strings.TrimSpace(v3diffWarning))\n\t}\n\n\treturn err\n}\n\nfunc getSize(ctx context.Context, sourcePath, builtPath, tags string) (int64, error) {\n\targs := []string{\"build\"}\n\n\tif tags != \"\" {\n\t\targs = append(args, []string{\"-tags\", tags}...)\n\t}\n\n\targs = append(args, []string{\n\t\t\"-o\", builtPath,\n\t\t\"-ldflags\", \"-s -w\",\n\t\tsourcePath,\n\t}...)\n\n\tif err := runCmd(ctx, \"go\", args...); err != nil {\n\t\tfmt.Println(\"issue getting size for example binary\")\n\t\treturn 0, err\n\t}\n\n\tfileInfo, err := os.Stat(builtPath)\n\tif err != nil {\n\t\tfmt.Println(\"issue getting size for example binary\")\n\t\treturn 0, err\n\t}\n\n\treturn fileInfo.Size(), nil\n}\n"
  },
  {
    "path": "sort.go",
    "content": "package cli\n\nimport \"unicode\"\n\n// lexicographicLess compares strings alphabetically considering case.\nfunc lexicographicLess(i, j string) bool {\n\tiRunes := []rune(i)\n\tjRunes := []rune(j)\n\n\tlenShared := len(iRunes)\n\tif lenShared > len(jRunes) {\n\t\tlenShared = len(jRunes)\n\t}\n\n\tfor index := 0; index < lenShared; index++ {\n\t\tir := iRunes[index]\n\t\tjr := jRunes[index]\n\n\t\tif lir, ljr := unicode.ToLower(ir), unicode.ToLower(jr); lir != ljr {\n\t\t\treturn lir < ljr\n\t\t}\n\n\t\tif ir != jr {\n\t\t\treturn ir < jr\n\t\t}\n\t}\n\n\treturn i < j\n}\n"
  },
  {
    "path": "sort_test.go",
    "content": "package cli\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar lexicographicLessTests = []struct {\n\ti        string\n\tj        string\n\texpected bool\n}{\n\t{\"\", \"a\", true},\n\t{\"a\", \"\", false},\n\t{\"a\", \"a\", false},\n\t{\"a\", \"A\", false},\n\t{\"A\", \"a\", true},\n\t{\"aa\", \"a\", false},\n\t{\"a\", \"aa\", true},\n\t{\"a\", \"b\", true},\n\t{\"a\", \"B\", true},\n\t{\"A\", \"b\", true},\n\t{\"A\", \"B\", true},\n}\n\nfunc TestLexicographicLess(t *testing.T) {\n\tfor _, test := range lexicographicLessTests {\n\t\tactual := lexicographicLess(test.i, test.j)\n\t\tassert.Equal(t, test.expected, actual)\n\t}\n}\n"
  },
  {
    "path": "staticcheck.conf",
    "content": "checks=[\"all\"]\n"
  },
  {
    "path": "suggestions.go",
    "content": "package cli\n\nimport (\n\t\"math\"\n)\n\nconst suggestDidYouMeanTemplate = \"Did you mean %q?\"\n\nvar (\n\tSuggestFlag               SuggestFlagFunc    = suggestFlag\n\tSuggestCommand            SuggestCommandFunc = suggestCommand\n\tSuggestDidYouMeanTemplate string             = suggestDidYouMeanTemplate\n)\n\ntype SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string\n\ntype SuggestCommandFunc func(commands []*Command, provided string) string\n\n// jaroDistance is the measure of similarity between two strings. It returns a\n// value between 0 and 1, where 1 indicates identical strings and 0 indicates\n// completely different strings.\n//\n// Adapted from https://github.com/xrash/smetrics/blob/5f08fbb34913bc8ab95bb4f2a89a0637ca922666/jaro.go.\nfunc jaroDistance(a, b string) float64 {\n\tif len(a) == 0 && len(b) == 0 {\n\t\treturn 1\n\t}\n\tif len(a) == 0 || len(b) == 0 {\n\t\treturn 0\n\t}\n\n\tlenA := float64(len(a))\n\tlenB := float64(len(b))\n\thashA := make([]bool, len(a))\n\thashB := make([]bool, len(b))\n\tmaxDistance := int(math.Max(0, math.Floor(math.Max(lenA, lenB)/2.0)-1))\n\n\tvar matches float64\n\tfor i := 0; i < len(a); i++ {\n\t\tstart := int(math.Max(0, float64(i-maxDistance)))\n\t\tend := int(math.Min(lenB-1, float64(i+maxDistance)))\n\n\t\tfor j := start; j <= end; j++ {\n\t\t\tif hashB[j] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif a[i] == b[j] {\n\t\t\t\thashA[i] = true\n\t\t\t\thashB[j] = true\n\t\t\t\tmatches++\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif matches == 0 {\n\t\treturn 0\n\t}\n\n\tvar transpositions float64\n\tvar j int\n\tfor i := 0; i < len(a); i++ {\n\t\tif !hashA[i] {\n\t\t\tcontinue\n\t\t}\n\t\tfor !hashB[j] {\n\t\t\tj++\n\t\t}\n\t\tif a[i] != b[j] {\n\t\t\ttranspositions++\n\t\t}\n\t\tj++\n\t}\n\n\ttranspositions /= 2\n\treturn ((matches / lenA) + (matches / lenB) + ((matches - transpositions) / matches)) / 3.0\n}\n\n// jaroWinkler is more accurate when strings have a common prefix up to a\n// defined maximum length.\n//\n// Adapted from https://github.com/xrash/smetrics/blob/5f08fbb34913bc8ab95bb4f2a89a0637ca922666/jaro-winkler.go.\nfunc jaroWinkler(a, b string) float64 {\n\tconst (\n\t\tboostThreshold = 0.7\n\t\tprefixSize     = 4\n\t)\n\tjaroDist := jaroDistance(a, b)\n\tif jaroDist <= boostThreshold {\n\t\treturn jaroDist\n\t}\n\n\tprefix := int(math.Min(float64(len(a)), math.Min(float64(prefixSize), float64(len(b)))))\n\n\tvar prefixMatch float64\n\tfor i := 0; i < prefix; i++ {\n\t\tif a[i] == b[i] {\n\t\t\tprefixMatch++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn jaroDist + 0.1*prefixMatch*(1.0-jaroDist)\n}\n\nfunc suggestFlag(flags []Flag, provided string, hideHelp bool) string {\n\tdistance := 0.0\n\tsuggestion := \"\"\n\n\tfor _, flag := range flags {\n\t\tflagNames := flag.Names()\n\t\tif !hideHelp && HelpFlag != nil {\n\t\t\tflagNames = append(flagNames, HelpFlag.Names()...)\n\t\t}\n\t\tfor _, name := range flagNames {\n\t\t\tnewDistance := jaroWinkler(name, provided)\n\t\t\tif newDistance > distance {\n\t\t\t\tdistance = newDistance\n\t\t\t\tsuggestion = name\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(suggestion) == 1 {\n\t\tsuggestion = \"-\" + suggestion\n\t} else if len(suggestion) > 1 {\n\t\tsuggestion = \"--\" + suggestion\n\t}\n\n\treturn suggestion\n}\n\n// suggestCommand takes a list of commands and a provided string to suggest a\n// command name\nfunc suggestCommand(commands []*Command, provided string) (suggestion string) {\n\tdistance := 0.0\n\tfor _, command := range commands {\n\t\tfor _, name := range append(command.Names(), helpName, helpAlias) {\n\t\t\tnewDistance := jaroWinkler(name, provided)\n\t\t\tif newDistance > distance {\n\t\t\t\tdistance = newDistance\n\t\t\t\tsuggestion = name\n\t\t\t}\n\t\t}\n\t}\n\n\treturn suggestion\n}\n"
  },
  {
    "path": "suggestions_test.go",
    "content": "package cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestJaroWinkler(t *testing.T) {\n\t// Given\n\tfor _, testCase := range []struct {\n\t\ta, b     string\n\t\texpected float64\n\t}{\n\t\t{\"\", \"\", 1},\n\t\t{\"a\", \"\", 0},\n\t\t{\"\", \"a\", 0},\n\t\t{\"a\", \"a\", 1},\n\t\t{\"a\", \"b\", 0},\n\t\t{\"aa\", \"aa\", 1},\n\t\t{\"aa\", \"bb\", 0},\n\t\t{\"aaa\", \"aaa\", 1},\n\t\t{\"aa\", \"ab\", 0.6666666666666666},\n\t\t{\"aa\", \"ba\", 0.6666666666666666},\n\t\t{\"ba\", \"aa\", 0.6666666666666666},\n\t\t{\"ab\", \"aa\", 0.6666666666666666},\n\t} {\n\t\t// When\n\t\tres := jaroWinkler(testCase.a, testCase.b)\n\n\t\t// Then\n\t\tassert.Equal(t, testCase.expected, res)\n\t}\n}\n\nfunc TestSuggestFlag(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\tfor _, testCase := range []struct {\n\t\tprovided, expected string\n\t}{\n\t\t{\"\", \"\"},\n\t\t{\"a\", \"--another-flag\"},\n\t\t{\"hlp\", \"--help\"},\n\t\t{\"k\", \"\"},\n\t\t{\"s\", \"-s\"},\n\t} {\n\t\t// When\n\t\tres := suggestFlag(app.Flags, testCase.provided, false)\n\n\t\t// Then\n\t\tassert.Equal(t, testCase.expected, res)\n\t}\n}\n\nfunc TestSuggestFlagHideHelp(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\t// When\n\tres := suggestFlag(app.Flags, \"hlp\", true)\n\n\t// Then\n\tassert.Equal(t, \"--fl\", res)\n}\n\nfunc TestSuggestFlagFromError(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\tfor _, testCase := range []struct {\n\t\tcommand, provided, expected string\n\t}{\n\t\t{\"\", \"hel\", \"--help\"},\n\t\t{\"\", \"soccer\", \"--socket\"},\n\t\t{\"config\", \"anot\", \"--another-flag\"},\n\t} {\n\t\t// When\n\t\tres, _ := app.suggestFlagFromError(\n\t\t\terrors.New(providedButNotDefinedErrMsg+testCase.provided),\n\t\t\ttestCase.command,\n\t\t)\n\n\t\t// Then\n\t\tassert.Equal(t, fmt.Sprintf(SuggestDidYouMeanTemplate+\"\\n\\n\", testCase.expected), res)\n\t}\n}\n\nfunc TestSuggestFlagFromErrorWrongError(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\t// When\n\t_, err := app.suggestFlagFromError(errors.New(\"invalid\"), \"\")\n\n\t// Then\n\tassert.Error(t, err)\n}\n\nfunc TestSuggestFlagFromErrorWrongCommand(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\t// When\n\t_, err := app.suggestFlagFromError(\n\t\terrors.New(providedButNotDefinedErrMsg+\"flag\"),\n\t\t\"invalid\",\n\t)\n\n\t// Then\n\tassert.Error(t, err)\n}\n\nfunc TestSuggestFlagFromErrorNoSuggestion(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\t// When\n\t_, err := app.suggestFlagFromError(\n\t\terrors.New(providedButNotDefinedErrMsg+\"\"),\n\t\t\"\",\n\t)\n\n\t// Then\n\tassert.Error(t, err)\n}\n\nfunc TestSuggestCommand(t *testing.T) {\n\t// Given\n\tapp := buildExtendedTestCommand()\n\n\tfor _, testCase := range []struct {\n\t\tprovided, expected string\n\t}{\n\t\t{\"\", \"\"},\n\t\t{\"conf\", \"config\"},\n\t\t{\"i\", \"i\"},\n\t\t{\"information\", \"info\"},\n\t\t{\"inf\", \"info\"},\n\t\t{\"con\", \"config\"},\n\t\t{\"not-existing\", \"info\"},\n\t} {\n\t\t// When\n\t\tres := suggestCommand(app.Commands, testCase.provided)\n\n\t\t// Then\n\t\tassert.Equal(t, testCase.expected, res)\n\t}\n}\n"
  },
  {
    "path": "template.go",
    "content": "package cli\n\nvar (\n\thelpNameTemplate    = `{{$v := offset .FullName 6}}{{wrap .FullName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}`\n\targsTemplate        = `{{if .Arguments}}{{range .Arguments}}{{.Usage}} {{end}}{{end}}`\n\tusageTemplate       = `{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleFlags}} [options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} {{template \"argsTemplate\" .}}{{end}}{{end}}{{end}}`\n\tdescriptionTemplate = `{{wrap .Description 3}}`\n\tauthorsTemplate     = `{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:\n   {{range $index, $author := .Authors}}{{if $index}}\n   {{end}}{{$author}}{{end}}`\n)\n\nvar visibleCommandTemplate = `{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}\n   {{$s := join .Names \", \"}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp \"\"}}{{wrap .Usage $cv}}{{end}}`\n\nvar visibleCommandCategoryTemplate = `{{range .VisibleCategories}}{{if .Name}}\n\n   {{.Name}}:{{range .VisibleCommands}}\n     {{join .Names \", \"}}{{\"\\t\"}}{{.Usage}}{{end}}{{else}}{{template \"visibleCommandTemplate\" .}}{{end}}{{end}}`\n\nvar visibleFlagCategoryTemplate = `{{range .VisibleFlagCategories}}\n   {{if .Name}}{{.Name}}\n\n   {{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}}\n{{else}}{{$e}}\n   {{end}}{{end}}{{end}}`\n\nvar visibleFlagTemplate = `{{range $i, $e := .VisibleFlags}}\n   {{wrap $e.String 6}}{{end}}`\n\nvar visiblePersistentFlagTemplate = `{{range $i, $e := .VisiblePersistentFlags}}\n   {{wrap $e.String 6}}{{end}}`\n\nvar versionTemplate = `{{if .Version}}{{if not .HideVersion}}\n\nVERSION:\n   {{.Version}}{{end}}{{end}}`\n\nvar copyrightTemplate = `{{wrap .Copyright 3}}`\n\n// RootCommandHelpTemplate is the text template for the Default help topic.\n// cli.go uses text/template to render templates. You can\n// render custom help text by setting this variable.\nvar RootCommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}} {{if .VisibleFlags}}[global options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}\n\nVERSION:\n   {{.Version}}{{end}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}\n{{- if len .Authors}}\n\nAUTHOR{{template \"authorsTemplate\" .}}{{end}}{{if .VisibleCommands}}\n\nCOMMANDS:{{template \"visibleCommandCategoryTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nGLOBAL OPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nGLOBAL OPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}{{if .Copyright}}\n\nCOPYRIGHT:\n   {{template \"copyrightTemplate\" .}}{{end}}\n`\n\n// CommandHelpTemplate is the text template for the command help topic.\n// cli.go uses text/template to render templates. You can\n// render custom help text by setting this variable.\nvar CommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{template \"usageTemplate\" .}}{{if .Category}}\n\nCATEGORY:\n   {{.Category}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nOPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nOPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}{{if .VisiblePersistentFlags}}\n\nGLOBAL OPTIONS:{{template \"visiblePersistentFlagTemplate\" .}}{{end}}\n`\n\n// SubcommandHelpTemplate is the text template for the subcommand help topic.\n// cli.go uses text/template to render templates. You can\n// render custom help text by setting this variable.\nvar SubcommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Category}}\n\nCATEGORY:\n   {{.Category}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}{{if .VisibleCommands}}\n\nCOMMANDS:{{template \"visibleCommandTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nOPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nOPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}\n`\n\nvar FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion\n\nfunction __fish_{{ .Command.Name }}_no_subcommand --description 'Test if there has been any subcommand yet'\n    for i in (commandline -opc)\n        if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }}\n            return 1\n        end\n    end\n    return 0\nend\n\n{{ range $v := .Completions }}{{ $v }}\n{{ end }}`\n"
  },
  {
    "path": "testdata/empty.yml",
    "content": "# empty file"
  },
  {
    "path": "testdata/expected-doc-full.man",
    "content": ".nh\n.TH greet 8\n\n.SH NAME\n.PP\ngreet - Some app\n\n\n.SH SYNOPSIS\n.PP\ngreet\n\n.PP\n.RS\n\n.nf\n[--another-flag|-b]\n[--flag|--fl|-f]=[value]\n[--socket|-s]=[value]\n\n.fi\n.RE\n\n\n.SH DESCRIPTION\n.PP\nDescription of the application.\n\n.PP\n\\fBUsage\\fP:\n\n.PP\n.RS\n\n.nf\napp [first_arg] [second_arg]\n\n.fi\n.RE\n\n\n.SH GLOBAL OPTIONS\n.PP\n\\fB--another-flag, -b\\fP: another usage text\n\n.PP\n\\fB--flag, --fl, -f\\fP=\"\":\n\n.PP\n\\fB--socket, -s\\fP=\"\": some 'usage' text (default: value)\n\n\n.SH COMMANDS\n.SH config, c\n.PP\nanother usage test\n\n.PP\n\\fB--another-flag, -b\\fP: another usage text\n\n.PP\n\\fB--flag, --fl, -f\\fP=\"\":\n\n.SS sub-config, s, ss\n.PP\nanother usage test\n\n.PP\n\\fB--sub-command-flag, -s\\fP: some usage text\n\n.PP\n\\fB--sub-flag, --sub-fl, -s\\fP=\"\":\n\n.SH info, i, in\n.PP\nretrieve generic information\n\n.SH some-command\n.SH usage, u\n.PP\nstandard usage text\n\n.PP\n.RS\n\n.nf\nUsage for the usage text\n- formatted:  Based on the specified ConfigMap and summon secrets.yml\n- list:       Inspect the environment for a specific process running on a Pod\n- for_effect: Compare 'namespace' environment with 'local'\n\n```\nfunc() { ... }\n```\n\nShould be a part of the same code block\n\n.fi\n.RE\n\n.PP\n\\fB--another-flag, -b\\fP: another usage text\n\n.PP\n\\fB--flag, --fl, -f\\fP=\"\":\n\n.SS sub-usage, su\n.PP\nstandard usage text\n\n.PP\n.RS\n\n.PP\nSingle line of UsageText\n\n.RE\n\n.PP\n\\fB--sub-command-flag, -s\\fP: some usage text\n"
  },
  {
    "path": "testdata/expected-doc-full.md",
    "content": "# NAME\n\ngreet - Some app\n\n# SYNOPSIS\n\ngreet\n\n```\n[--another-flag|-b]\n[--flag|--fl|-f]=[value]\n[--socket|-s]=[value]\n```\n\n# DESCRIPTION\n\nDescription of the application.\n\n**Usage**:\n\n```\napp [first_arg] [second_arg]\n```\n\n# GLOBAL OPTIONS\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n**--socket, -s**=\"\": some 'usage' text (default: value)\n\n\n# COMMANDS\n\n## config, c\n\nanother usage test\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-config, s, ss\n\nanother usage test\n\n**--sub-command-flag, -s**: some usage text\n\n**--sub-flag, --sub-fl, -s**=\"\": \n\n## info, i, in\n\nretrieve generic information\n\n## some-command\n\n\n## usage, u\n\nstandard usage text\n\n    Usage for the usage text\n    - formatted:  Based on the specified ConfigMap and summon secrets.yml\n    - list:       Inspect the environment for a specific process running on a Pod\n    - for_effect: Compare 'namespace' environment with 'local'\n    \n    ```\n    func() { ... }\n    ```\n    \n    Should be a part of the same code block\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-usage, su\n\nstandard usage text\n\n>Single line of UsageText\n\n**--sub-command-flag, -s**: some usage text\n"
  },
  {
    "path": "testdata/expected-doc-no-authors.md",
    "content": "# NAME\n\ngreet - Some app\n\n# SYNOPSIS\n\ngreet\n\n```\n[--another-flag|-b]\n[--flag|--fl|-f]=[value]\n[--socket|-s]=[value]\n```\n\n# DESCRIPTION\n\nDescription of the application.\n\n**Usage**:\n\n```\napp [first_arg] [second_arg]\n```\n\n# GLOBAL OPTIONS\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n**--socket, -s**=\"\": some 'usage' text (default: value)\n\n\n# COMMANDS\n\n## config, c\n\nanother usage test\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-config, s, ss\n\nanother usage test\n\n**--sub-command-flag, -s**: some usage text\n\n**--sub-flag, --sub-fl, -s**=\"\": \n\n## info, i, in\n\nretrieve generic information\n\n## some-command\n\n\n## usage, u\n\nstandard usage text\n\n    Usage for the usage text\n    - formatted:  Based on the specified ConfigMap and summon secrets.yml\n    - list:       Inspect the environment for a specific process running on a Pod\n    - for_effect: Compare 'namespace' environment with 'local'\n    \n    ```\n    func() { ... }\n    ```\n    \n    Should be a part of the same code block\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-usage, su\n\nstandard usage text\n\n>Single line of UsageText\n\n**--sub-command-flag, -s**: some usage text\n"
  },
  {
    "path": "testdata/expected-doc-no-commands.md",
    "content": "# NAME\n\ngreet - Some app\n\n# SYNOPSIS\n\ngreet\n\n```\n[--another-flag|-b]\n[--flag|--fl|-f]=[value]\n[--socket|-s]=[value]\n```\n\n# DESCRIPTION\n\nDescription of the application.\n\n**Usage**:\n\n```\napp [first_arg] [second_arg]\n```\n\n# GLOBAL OPTIONS\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n**--socket, -s**=\"\": some 'usage' text (default: value)\n\n"
  },
  {
    "path": "testdata/expected-doc-no-flags.md",
    "content": "# NAME\n\ngreet - Some app\n\n# SYNOPSIS\n\ngreet\n\n# DESCRIPTION\n\nDescription of the application.\n\n**Usage**:\n\n```\napp [first_arg] [second_arg]\n```\n\n# COMMANDS\n\n## config, c\n\nanother usage test\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-config, s, ss\n\nanother usage test\n\n**--sub-command-flag, -s**: some usage text\n\n**--sub-flag, --sub-fl, -s**=\"\": \n\n## info, i, in\n\nretrieve generic information\n\n## some-command\n\n\n## usage, u\n\nstandard usage text\n\n    Usage for the usage text\n    - formatted:  Based on the specified ConfigMap and summon secrets.yml\n    - list:       Inspect the environment for a specific process running on a Pod\n    - for_effect: Compare 'namespace' environment with 'local'\n    \n    ```\n    func() { ... }\n    ```\n    \n    Should be a part of the same code block\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-usage, su\n\nstandard usage text\n\n>Single line of UsageText\n\n**--sub-command-flag, -s**: some usage text\n"
  },
  {
    "path": "testdata/expected-doc-no-usagetext.md",
    "content": "# NAME\n\ngreet - Some app\n\n# SYNOPSIS\n\ngreet\n\n```\n[--another-flag|-b]\n[--flag|--fl|-f]=[value]\n[--socket|-s]=[value]\n```\n\n# DESCRIPTION\n\nDescription of the application.\n\n**Usage**:\n\n```\ngreet [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]\n```\n\n# GLOBAL OPTIONS\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n**--socket, -s**=\"\": some 'usage' text (default: value)\n\n\n# COMMANDS\n\n## config, c\n\nanother usage test\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-config, s, ss\n\nanother usage test\n\n**--sub-command-flag, -s**: some usage text\n\n**--sub-flag, --sub-fl, -s**=\"\": \n\n## info, i, in\n\nretrieve generic information\n\n## some-command\n\n\n## usage, u\n\nstandard usage text\n\n    Usage for the usage text\n    - formatted:  Based on the specified ConfigMap and summon secrets.yml\n    - list:       Inspect the environment for a specific process running on a Pod\n    - for_effect: Compare 'namespace' environment with 'local'\n    \n    ```\n    func() { ... }\n    ```\n    \n    Should be a part of the same code block\n\n**--another-flag, -b**: another usage text\n\n**--flag, --fl, -f**=\"\": \n\n### sub-usage, su\n\nstandard usage text\n\n>Single line of UsageText\n\n**--sub-command-flag, -s**: some usage text\n"
  },
  {
    "path": "testdata/expected-fish-full.fish",
    "content": "# greet fish shell completion\n\nfunction __fish_greet_no_subcommand --description 'Test if there has been any subcommand yet'\n    for i in (commandline -opc)\n        if contains -- $i config c info i in some-command hidden-command usage u\n            return 1\n        end\n    end\n    return 0\nend\n\ncomplete -c greet -n '__fish_greet_no_subcommand' -l socket -s s -r -d 'some \\'usage\\' text'\ncomplete -c greet -n '__fish_greet_no_subcommand' -f -l flag -s fl -s f -r\ncomplete -c greet -n '__fish_greet_no_subcommand' -f -l another-flag -s b -d 'another usage text'\ncomplete -c greet -n '__fish_greet_no_subcommand' -l logfile -r\ncomplete -c greet -n '__fish_greet_no_subcommand' -l foofile -r\ncomplete -x -c greet -n '__fish_greet_no_subcommand' -a 'config' -d 'another usage test'\ncomplete -c greet -n '__fish_seen_subcommand_from config c' -l flag -s fl -s f -r\ncomplete -c greet -n '__fish_seen_subcommand_from config c' -f -l another-flag -s b -d 'another usage text'\ncomplete -c greet -n '__fish_seen_subcommand_from config c' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss help h' -a 'sub-config' -d 'another usage test'\ncomplete -c greet -n '__fish_seen_subcommand_from config c; and __fish_seen_subcommand_from sub-config s ss' -f -l sub-flag -s sub-fl -s s -r\ncomplete -c greet -n '__fish_seen_subcommand_from config c; and __fish_seen_subcommand_from sub-config s ss' -f -l sub-command-flag -s s -d 'some usage text'\ncomplete -c greet -n '__fish_seen_subcommand_from config c; and __fish_seen_subcommand_from sub-config s ss' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from config c; and __fish_seen_subcommand_from sub-config s ss; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command'\ncomplete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss help h' -a 'help' -d 'Shows a list of commands or help for one command'\ncomplete -x -c greet -n '__fish_greet_no_subcommand' -a 'info' -d 'retrieve generic information'\ncomplete -c greet -n '__fish_seen_subcommand_from info i in' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from info i in; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command'\ncomplete -x -c greet -n '__fish_greet_no_subcommand' -a 'some-command'\ncomplete -c greet -n '__fish_seen_subcommand_from some-command' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from some-command; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command'\ncomplete -c greet -n '__fish_seen_subcommand_from hidden-command' -f -l completable\ncomplete -c greet -n '__fish_seen_subcommand_from hidden-command' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from hidden-command; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command'\ncomplete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage' -d 'standard usage text'\ncomplete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r\ncomplete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text'\ncomplete -c greet -n '__fish_seen_subcommand_from usage u' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su help h' -a 'sub-usage' -d 'standard usage text'\ncomplete -c greet -n '__fish_seen_subcommand_from usage u; and __fish_seen_subcommand_from sub-usage su' -f -l sub-command-flag -s s -d 'some usage text'\ncomplete -c greet -n '__fish_seen_subcommand_from usage u; and __fish_seen_subcommand_from sub-usage su' -f -l help -s h -d 'show help'\ncomplete -x -c greet -n '__fish_seen_subcommand_from usage u; and __fish_seen_subcommand_from sub-usage su; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command'\ncomplete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su help h' -a 'help' -d 'Shows a list of commands or help for one command'\n"
  },
  {
    "path": "testdata/expected-tabular-markdown-custom-app-path.md",
    "content": "## CLI interface - greet\n\nDescription of the application.\n\nSome app.\n\n> app [first_arg] [second_arg]\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] [COMMAND] [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nGlobal flags:\n\n| Name                        | Description        | Default value |  Environment variables  |\n|-----------------------------|--------------------|:-------------:|:-----------------------:|\n| `--socket=\"…\"` (`-s`)       | some 'usage' text  |    `value`    |         *none*          |\n| `--flag=\"…\"` (`--fl`, `-f`) |                    |               |         *none*          |\n| `--another-flag` (`-b`)     | another usage text |    `false`    | `EXAMPLE_VARIABLE_NAME` |\n\n### `config` command (aliases: `c`)\n\nanother usage test.\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] config [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                        | Description        | Default value | Environment variables |\n|-----------------------------|--------------------|:-------------:|:---------------------:|\n| `--flag=\"…\"` (`--fl`, `-f`) |                    |               |        *none*         |\n| `--another-flag` (`-b`)     | another usage text |    `false`    |        *none*         |\n\n### `config sub-config` subcommand (aliases: `s`, `ss`)\n\nanother usage test.\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] config sub-config [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                                | Description     | Default value | Environment variables |\n|-------------------------------------|-----------------|:-------------:|:---------------------:|\n| `--sub-flag=\"…\"` (`--sub-fl`, `-s`) |                 |               |        *none*         |\n| `--sub-command-flag` (`-s`)         | some usage text |    `false`    |        *none*         |\n\n### `info` command (aliases: `i`, `in`)\n\nretrieve generic information.\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] info [ARGUMENTS...]\n```\n\n### `some-command` command\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] some-command [ARGUMENTS...]\n```\n\n### `usage` command (aliases: `u`)\n\nstandard usage text.\n\n> Usage for the usage text\n> - formatted:  Based on the specified ConfigMap and summon secrets.yml\n> - list:       Inspect the environment for a specific process running on a Pod\n> - for_effect: Compare 'namespace' environment with 'local'\n> ```\n> func() { ... }\n> ```\n> Should be a part of the same code block\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] usage [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                        | Description        | Default value | Environment variables |\n|-----------------------------|--------------------|:-------------:|:---------------------:|\n| `--flag=\"…\"` (`--fl`, `-f`) |                    |               |        *none*         |\n| `--another-flag` (`-b`)     | another usage text |    `false`    |        *none*         |\n\n### `usage sub-usage` subcommand (aliases: `su`)\n\nstandard usage text.\n\n> Single line of UsageText\n\nUsage:\n\n```bash\n$ /usr/local/bin [GLOBAL FLAGS] usage sub-usage [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                        | Description     | Default value | Environment variables |\n|-----------------------------|-----------------|:-------------:|:---------------------:|\n| `--sub-command-flag` (`-s`) | some usage text |    `false`    |        *none*         |\n"
  },
  {
    "path": "testdata/expected-tabular-markdown-full.md",
    "content": "## CLI interface - greet\n\nDescription of the application.\n\nSome app.\n\n> app [first_arg] [second_arg]\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] [COMMAND] [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nGlobal flags:\n\n| Name                        | Description        | Default value |  Environment variables  |\n|-----------------------------|--------------------|:-------------:|:-----------------------:|\n| `--socket=\"…\"` (`-s`)       | some 'usage' text  |    `value`    |         *none*          |\n| `--flag=\"…\"` (`--fl`, `-f`) |                    |               |         *none*          |\n| `--another-flag` (`-b`)     | another usage text |    `false`    | `EXAMPLE_VARIABLE_NAME` |\n\n### `config` command (aliases: `c`)\n\nanother usage test.\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] config [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                        | Description        | Default value | Environment variables |\n|-----------------------------|--------------------|:-------------:|:---------------------:|\n| `--flag=\"…\"` (`--fl`, `-f`) |                    |               |        *none*         |\n| `--another-flag` (`-b`)     | another usage text |    `false`    |        *none*         |\n\n### `config sub-config` subcommand (aliases: `s`, `ss`)\n\nanother usage test.\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] config sub-config [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                                | Description     | Default value | Environment variables |\n|-------------------------------------|-----------------|:-------------:|:---------------------:|\n| `--sub-flag=\"…\"` (`--sub-fl`, `-s`) |                 |               |        *none*         |\n| `--sub-command-flag` (`-s`)         | some usage text |    `false`    |        *none*         |\n\n### `info` command (aliases: `i`, `in`)\n\nretrieve generic information.\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] info [ARGUMENTS...]\n```\n\n### `some-command` command\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] some-command [ARGUMENTS...]\n```\n\n### `usage` command (aliases: `u`)\n\nstandard usage text.\n\n> Usage for the usage text\n> - formatted:  Based on the specified ConfigMap and summon secrets.yml\n> - list:       Inspect the environment for a specific process running on a Pod\n> - for_effect: Compare 'namespace' environment with 'local'\n> ```\n> func() { ... }\n> ```\n> Should be a part of the same code block\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] usage [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                        | Description        | Default value | Environment variables |\n|-----------------------------|--------------------|:-------------:|:---------------------:|\n| `--flag=\"…\"` (`--fl`, `-f`) |                    |               |        *none*         |\n| `--another-flag` (`-b`)     | another usage text |    `false`    |        *none*         |\n\n### `usage sub-usage` subcommand (aliases: `su`)\n\nstandard usage text.\n\n> Single line of UsageText\n\nUsage:\n\n```bash\n$ app [GLOBAL FLAGS] usage sub-usage [COMMAND FLAGS] [ARGUMENTS...]\n```\n\nThe following flags are supported:\n\n| Name                        | Description     | Default value | Environment variables |\n|-----------------------------|-----------------|:-------------:|:---------------------:|\n| `--sub-command-flag` (`-s`) | some usage text |    `false`    |        *none*         |\n"
  },
  {
    "path": "testdata/godoc-v3.x.txt",
    "content": "package cli // import \"github.com/urfave/cli/v3\"\n\nPackage cli provides a minimal framework for creating and organizing command\nline Go applications. cli is designed to be easy to understand and write,\nthe most simple cli application can be written as follows:\n\n    func main() {\n    \t(&cli.Command{}).Run(context.Background(), os.Args)\n    }\n\nOf course this application does not do much, so let's make this an actual\napplication:\n\n    func main() {\n    \tcmd := &cli.Command{\n      \t\tName: \"greet\",\n      \t\tUsage: \"say a greeting\",\n      \t\tAction: func(c *cli.Context) error {\n      \t\t\tfmt.Println(\"Greetings\")\n      \t\t\treturn nil\n      \t\t},\n    \t}\n\n    \tcmd.Run(context.Background(), os.Args)\n    }\n\nVARIABLES\n\nvar (\n\tNewFloatSlice   = NewSliceBase[float64, NoConfig, floatValue[float64]]\n\tNewFloat32Slice = NewSliceBase[float32, NoConfig, floatValue[float32]]\n\tNewFloat64Slice = NewSliceBase[float64, NoConfig, floatValue[float64]]\n)\nvar (\n\tNewIntSlice   = NewSliceBase[int, IntegerConfig, intValue[int]]\n\tNewInt8Slice  = NewSliceBase[int8, IntegerConfig, intValue[int8]]\n\tNewInt16Slice = NewSliceBase[int16, IntegerConfig, intValue[int16]]\n\tNewInt32Slice = NewSliceBase[int32, IntegerConfig, intValue[int32]]\n\tNewInt64Slice = NewSliceBase[int64, IntegerConfig, intValue[int64]]\n)\nvar (\n\tNewUintSlice   = NewSliceBase[uint, IntegerConfig, uintValue[uint]]\n\tNewUint8Slice  = NewSliceBase[uint8, IntegerConfig, uintValue[uint8]]\n\tNewUint16Slice = NewSliceBase[uint16, IntegerConfig, uintValue[uint16]]\n\tNewUint32Slice = NewSliceBase[uint32, IntegerConfig, uintValue[uint32]]\n\tNewUint64Slice = NewSliceBase[uint64, IntegerConfig, uintValue[uint64]]\n)\nvar (\n\tSuggestFlag               SuggestFlagFunc    = suggestFlag\n\tSuggestCommand            SuggestCommandFunc = suggestCommand\n\tSuggestDidYouMeanTemplate string             = suggestDidYouMeanTemplate\n)\nvar AnyArguments = []Argument{\n\t&StringArgs{\n\t\tMax: -1,\n\t},\n}\n    AnyArguments to differentiate between no arguments(nil) vs aleast one\n\nvar ArgsUsageCommandHelp = \"[command]\"\n    ArgsUsageCommandHelp is a short description of the arguments of the help\n    command\n\nvar CommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{template \"usageTemplate\" .}}{{if .Category}}\n\nCATEGORY:\n   {{.Category}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nOPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nOPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}{{if .VisiblePersistentFlags}}\n\nGLOBAL OPTIONS:{{template \"visiblePersistentFlagTemplate\" .}}{{end}}\n`\n    CommandHelpTemplate is the text template for the command help topic. cli.go\n    uses text/template to render templates. You can render custom help text by\n    setting this variable.\n\nvar DefaultAppComplete = DefaultRootCommandComplete\n    DefaultAppComplete is a backward-compatible name for\n    DefaultRootCommandComplete.\n\nvar DefaultInverseBoolPrefix = \"no-\"\nvar ErrWriter io.Writer = os.Stderr\n    ErrWriter is used to write errors to the user. This can be anything\n    implementing the io.Writer interface and defaults to os.Stderr.\n\nvar FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion\n\nfunction __fish_{{ .Command.Name }}_no_subcommand --description 'Test if there has been any subcommand yet'\n    for i in (commandline -opc)\n        if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }}\n            return 1\n        end\n    end\n    return 0\nend\n\n{{ range $v := .Completions }}{{ $v }}\n{{ end }}`\nvar NewStringMap = NewMapBase[string, StringConfig, stringValue]\nvar NewStringSlice = NewSliceBase[string, StringConfig, stringValue]\nvar OsExiter = os.Exit\n    OsExiter is the function used when the app exits. If not set defaults to\n    os.Exit.\n\nvar RootCommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}} {{if .VisibleFlags}}[global options]{{end}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}\n\nVERSION:\n   {{.Version}}{{end}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}\n{{- if len .Authors}}\n\nAUTHOR{{template \"authorsTemplate\" .}}{{end}}{{if .VisibleCommands}}\n\nCOMMANDS:{{template \"visibleCommandCategoryTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nGLOBAL OPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nGLOBAL OPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}{{if .Copyright}}\n\nCOPYRIGHT:\n   {{template \"copyrightTemplate\" .}}{{end}}\n`\n    RootCommandHelpTemplate is the text template for the Default help topic.\n    cli.go uses text/template to render templates. You can render custom help\n    text by setting this variable.\n\nvar ShowAppHelp = ShowRootCommandHelp\n    ShowAppHelp is a backward-compatible name for ShowRootCommandHelp.\n\nvar ShowAppHelpAndExit = ShowRootCommandHelpAndExit\n    ShowAppHelpAndExit is a backward-compatible name for ShowRootCommandHelp.\n\nvar ShowCommandHelp = DefaultShowCommandHelp\n    ShowCommandHelp prints help for the given command\n\nvar ShowRootCommandHelp = DefaultShowRootCommandHelp\n    ShowRootCommandHelp is an action that displays help for the root command.\n\nvar ShowSubcommandHelp = DefaultShowSubcommandHelp\n    ShowSubcommandHelp prints help for the given subcommand\n\nvar SubcommandHelpTemplate = `NAME:\n   {{template \"helpNameTemplate\" .}}\n\nUSAGE:\n   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.FullName}}{{if .VisibleCommands}} [command [command options]]{{end}}{{if .ArgsUsage}} {{.ArgsUsage}}{{else}}{{if .Arguments}} [arguments...]{{end}}{{end}}{{end}}{{if .Category}}\n\nCATEGORY:\n   {{.Category}}{{end}}{{if .Description}}\n\nDESCRIPTION:\n   {{template \"descriptionTemplate\" .}}{{end}}{{if .VisibleCommands}}\n\nCOMMANDS:{{template \"visibleCommandTemplate\" .}}{{end}}{{if .VisibleFlagCategories}}\n\nOPTIONS:{{template \"visibleFlagCategoryTemplate\" .}}{{else if .VisibleFlags}}\n\nOPTIONS:{{template \"visibleFlagTemplate\" .}}{{end}}\n`\n    SubcommandHelpTemplate is the text template for the subcommand help topic.\n    cli.go uses text/template to render templates. You can render custom help\n    text by setting this variable.\n\nvar UsageCommandHelp = \"Shows a list of commands or help for one command\"\n    UsageCommandHelp is the text to override the USAGE section of the help\n    command\n\nvar VersionPrinter = DefaultPrintVersion\n    VersionPrinter prints the version for the root Command.\n\n\nFUNCTIONS\n\nfunc DefaultCompleteWithFlags(ctx context.Context, cmd *Command)\nfunc DefaultPrintHelp(out io.Writer, templ string, data any)\n    DefaultPrintHelp is the default implementation of HelpPrinter.\n\nfunc DefaultPrintHelpCustom(out io.Writer, templ string, data any, customFuncs map[string]any)\n    DefaultPrintHelpCustom is the default implementation of HelpPrinterCustom.\n\n    The customFuncs map will be combined with a default template.FuncMap to\n    allow using arbitrary functions in template rendering.\n\nfunc DefaultPrintVersion(cmd *Command)\n    DefaultPrintVersion is the default implementation of VersionPrinter.\n\nfunc DefaultRootCommandComplete(ctx context.Context, cmd *Command)\n    DefaultRootCommandComplete prints the list of subcommands as the default\n    completion method.\n\nfunc DefaultShowCommandHelp(ctx context.Context, cmd *Command, commandName string) error\n    DefaultShowCommandHelp is the default implementation of ShowCommandHelp.\n\nfunc DefaultShowRootCommandHelp(cmd *Command) error\n    DefaultShowRootCommandHelp is the default implementation of\n    ShowRootCommandHelp.\n\nfunc DefaultShowSubcommandHelp(cmd *Command) error\n    DefaultShowSubcommandHelp is the default implementation of\n    ShowSubcommandHelp.\n\nfunc FlagNames(name string, aliases []string) []string\nfunc HandleExitCoder(err error)\n    HandleExitCoder handles errors implementing ExitCoder by printing their\n    message and calling OsExiter with the given exit code.\n\n    If the given error instead implements MultiError, each error will be checked\n    for the ExitCoder interface, and OsExiter will be called with the last exit\n    code found, or exit code 1 if no ExitCoder is found.\n\n    This function is the default error-handling behavior for a Command.\n\nfunc ShowCommandHelpAndExit(ctx context.Context, cmd *Command, command string, code int)\n    ShowCommandHelpAndExit exits with code after showing help via\n    ShowCommandHelp.\n\nfunc ShowRootCommandHelpAndExit(cmd *Command, exitCode int)\n    ShowRootCommandHelpAndExit prints the list of subcommands and exits with\n    exit code.\n\nfunc ShowSubcommandHelpAndExit(cmd *Command, exitCode int)\n    ShowSubcommandHelpAndExit prints help for the given subcommand via\n    ShowSubcommandHelp and exits with exit code.\n\nfunc ShowVersion(cmd *Command)\n    ShowVersion prints the version number of the root Command.\n\n\nTYPES\n\ntype ActionFunc func(context.Context, *Command) error\n    ActionFunc is the action to execute when no subcommands are specified\n\ntype ActionableFlag interface {\n\tRunAction(context.Context, *Command) error\n}\n    ActionableFlag is an interface that wraps Flag interface and RunAction\n    operation.\n\ntype AfterFunc func(context.Context, *Command) error\n    AfterFunc is an action that executes after any subcommands are run and have\n    finished. The AfterFunc is run even if Action() panics.\n\ntype Args interface {\n\t// Get returns the nth argument, or else a blank string\n\tGet(n int) string\n\t// First returns the first argument, or else a blank string\n\tFirst() string\n\t// Tail returns the rest of the arguments (not the first one)\n\t// or else an empty string slice\n\tTail() []string\n\t// Len returns the length of the wrapped slice\n\tLen() int\n\t// Present checks if there are any arguments present\n\tPresent() bool\n\t// Slice returns a copy of the internal slice\n\tSlice() []string\n}\n\ntype Argument interface {\n\t// which this argument can be accessed using the given name\n\tHasName(string) bool\n\n\t// Parse the given args and return unparsed args and/or error\n\tParse([]string) ([]string, error)\n\n\t// The usage template for this argument to use in help\n\tUsage() string\n\n\t// The Value of this Arg\n\tGet() any\n}\n    Argument captures a positional argument that can be parsed\n\ntype ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName        string `json:\"name\"`      // the name of this argument\n\tValue       T      `json:\"value\"`     // the default value of this argument\n\tDestination *T     `json:\"-\"`         // the destination point for this argument\n\tUsageText   string `json:\"usageText\"` // the usage text to show\n\tConfig      C      `json:\"config\"`    // config for this argument similar to Flag Config\n\n\t// Has unexported fields.\n}\n\nfunc (a *ArgumentBase[T, C, VC]) Get() any\n\nfunc (a *ArgumentBase[T, C, VC]) HasName(s string) bool\n\nfunc (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error)\n\nfunc (a *ArgumentBase[T, C, VC]) Usage() string\n\ntype ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName        string `json:\"name\"`      // the name of this argument\n\tValue       T      `json:\"value\"`     // the default value of this argument\n\tDestination *[]T   `json:\"-\"`         // the destination point for this argument\n\tUsageText   string `json:\"usageText\"` // the usage text to show\n\tMin         int    `json:\"minTimes\"`  // the min num of occurrences of this argument\n\tMax         int    `json:\"maxTimes\"`  // the max num of occurrences of this argument, set to -1 for unlimited\n\tConfig      C      `json:\"config\"`    // config for this argument similar to Flag Config\n\n\t// Has unexported fields.\n}\n    ArgumentsBase is a base type for slice arguments\n\nfunc (a *ArgumentsBase[T, C, VC]) Get() any\n\nfunc (a *ArgumentsBase[T, C, VC]) HasName(s string) bool\n\nfunc (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error)\n\nfunc (a *ArgumentsBase[T, C, VC]) Usage() string\n\ntype BeforeFunc func(context.Context, *Command) (context.Context, error)\n    BeforeFunc is an action that executes prior to any subcommands being run\n    once the context is ready. If a non-nil error is returned, no subcommands\n    are run.\n\ntype BoolConfig struct {\n\tCount *int\n}\n    BoolConfig defines the configuration for bool flags\n\ntype BoolFlag = FlagBase[bool, BoolConfig, boolValue]\n\ntype BoolWithInverseFlag struct {\n\tName             string                                      `json:\"name\"`             // name of the flag\n\tCategory         string                                      `json:\"category\"`         // category of the flag, if any\n\tDefaultText      string                                      `json:\"defaultText\"`      // default text of the flag for usage purposes\n\tHideDefault      bool                                        `json:\"hideDefault\"`      // whether to hide the default value in output\n\tUsage            string                                      `json:\"usage\"`            // usage string for help output\n\tSources          ValueSourceChain                            `json:\"-\"`                // sources to load flag value from\n\tRequired         bool                                        `json:\"required\"`         // whether the flag is required or not\n\tHidden           bool                                        `json:\"hidden\"`           // whether to hide the flag in help output\n\tLocal            bool                                        `json:\"local\"`            // whether the flag needs to be applied to subcommands as well\n\tValue            bool                                        `json:\"defaultValue\"`     // default value for this flag if not set by from any source\n\tDestination      *bool                                       `json:\"-\"`                // destination pointer for value when set\n\tAliases          []string                                    `json:\"aliases\"`          // Aliases that are allowed for this flag\n\tTakesFile        bool                                        `json:\"takesFileArg\"`     // whether this flag takes a file argument, mainly for shell completion purposes\n\tAction           func(context.Context, *Command, bool) error `json:\"-\"`                // Action callback to be called when flag is set\n\tOnlyOnce         bool                                        `json:\"onlyOnce\"`         // whether this flag can be duplicated on the command line\n\tValidator        func(bool) error                            `json:\"-\"`                // custom function to validate this flag value\n\tValidateDefaults bool                                        `json:\"validateDefaults\"` // whether to validate defaults or not\n\tConfig           BoolConfig                                  `json:\"config\"`           // Additional/Custom configuration associated with this flag type\n\tInversePrefix    string                                      `json:\"invPrefix\"`        // The prefix used to indicate a negative value. Default: `env` becomes `no-env`\n\n\t// Has unexported fields.\n}\n\nfunc (bif *BoolWithInverseFlag) Count() int\n    Count returns the number of times this flag has been invoked\n\nfunc (bif *BoolWithInverseFlag) Get() any\n\nfunc (bif *BoolWithInverseFlag) GetCategory() string\n    GetCategory returns the category of the flag\n\nfunc (bif *BoolWithInverseFlag) GetDefaultText() string\n    GetDefaultText returns the default text for this flag\n\nfunc (bif *BoolWithInverseFlag) GetEnvVars() []string\n    GetEnvVars returns the env vars for this flag\n\nfunc (bif *BoolWithInverseFlag) GetUsage() string\n    GetUsage returns the usage string for the flag\n\nfunc (bif *BoolWithInverseFlag) GetValue() string\n    GetValue returns the flags value as string representation and an empty\n    string if the flag takes no value at all.\n\nfunc (bif *BoolWithInverseFlag) IsBoolFlag() bool\n    IsBoolFlag returns whether the flag doesnt need to accept args\n\nfunc (bif *BoolWithInverseFlag) IsDefaultVisible() bool\n    IsDefaultVisible returns true if the flag is not hidden, otherwise false\n\nfunc (bif *BoolWithInverseFlag) IsLocal() bool\n\nfunc (bif *BoolWithInverseFlag) IsRequired() bool\n\nfunc (bif *BoolWithInverseFlag) IsSet() bool\n\nfunc (bif *BoolWithInverseFlag) IsVisible() bool\n\nfunc (bif *BoolWithInverseFlag) Names() []string\n\nfunc (bif *BoolWithInverseFlag) PostParse() error\n\nfunc (bif *BoolWithInverseFlag) PreParse() error\n\nfunc (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error\n\nfunc (bif *BoolWithInverseFlag) Set(name, val string) error\n\nfunc (bif *BoolWithInverseFlag) SetCategory(c string)\n\nfunc (bif *BoolWithInverseFlag) String() string\n    String implements the standard Stringer interface.\n\n    Example for BoolFlag{Name: \"env\"} --[no-]env (default: false)\n\nfunc (bif *BoolWithInverseFlag) TakesValue() bool\n\nfunc (bif *BoolWithInverseFlag) TypeName() string\n    TypeName is used for stringify/docs. For bool its a no-op\n\ntype CategorizableFlag interface {\n\t// Returns the category of the flag\n\tGetCategory() string\n\n\t// Sets the category of the flag\n\tSetCategory(string)\n}\n    CategorizableFlag is an interface that allows us to potentially use a flag\n    in a categorized representation.\n\ntype Command struct {\n\t// The name of the command\n\tName string `json:\"name\"`\n\t// A list of aliases for the command\n\tAliases []string `json:\"aliases\"`\n\t// A short description of the usage of this command\n\tUsage string `json:\"usage\"`\n\t// Text to override the USAGE section of help\n\tUsageText string `json:\"usageText\"`\n\t// A short description of the arguments of this command\n\tArgsUsage string `json:\"argsUsage\"`\n\t// Version of the command\n\tVersion string `json:\"version\"`\n\t// Longer explanation of how the command works\n\tDescription string `json:\"description\"`\n\t// DefaultCommand is the (optional) name of a command\n\t// to run if no command names are passed as CLI arguments.\n\tDefaultCommand string `json:\"defaultCommand\"`\n\t// The category the command is part of\n\tCategory string `json:\"category\"`\n\t// List of child commands\n\tCommands []*Command `json:\"commands\"`\n\t// List of flags to parse\n\tFlags []Flag `json:\"flags\"`\n\t// Boolean to hide built-in help command and help flag\n\tHideHelp bool `json:\"hideHelp\"`\n\t// Ignored if HideHelp is true.\n\tHideHelpCommand bool `json:\"hideHelpCommand\"`\n\t// Boolean to hide built-in version flag and the VERSION section of help\n\tHideVersion bool `json:\"hideVersion\"`\n\t// Boolean to enable shell completion commands\n\tEnableShellCompletion bool `json:\"-\"`\n\t// Shell Completion generation command name\n\tShellCompletionCommandName string `json:\"-\"`\n\t// The function to call when checking for shell command completions\n\tShellComplete ShellCompleteFunc `json:\"-\"`\n\t// The function to configure a shell completion command\n\tConfigureShellCompletionCommand ConfigureShellCompletionCommand `json:\"-\"`\n\t// An action to execute before any subcommands are run, but after the context is ready\n\t// If a non-nil error is returned, no subcommands are run\n\tBefore BeforeFunc `json:\"-\"`\n\t// An action to execute after any subcommands are run, but after the subcommand has finished\n\t// It is run even if Action() panics\n\tAfter AfterFunc `json:\"-\"`\n\t// The function to call when this command is invoked\n\tAction ActionFunc `json:\"-\"`\n\t// Execute this function if the proper command cannot be found\n\tCommandNotFound CommandNotFoundFunc `json:\"-\"`\n\t// Execute this function if a usage error occurs.\n\tOnUsageError OnUsageErrorFunc `json:\"-\"`\n\t// Execute this function when an invalid flag is accessed from the context\n\tInvalidFlagAccessHandler InvalidFlagAccessFunc `json:\"-\"`\n\t// Boolean to hide this command from help or completion\n\tHidden bool `json:\"hidden\"`\n\t// List of all authors who contributed (string or fmt.Stringer)\n\t// TODO: ~string | fmt.Stringer when interface unions are available\n\tAuthors []any `json:\"authors\"`\n\t// Copyright of the binary if any\n\tCopyright string `json:\"copyright\"`\n\t// Reader reader to write input to (useful for tests)\n\tReader io.Reader `json:\"-\"`\n\t// Writer writer to write output to\n\tWriter io.Writer `json:\"-\"`\n\t// ErrWriter writes error output\n\tErrWriter io.Writer `json:\"-\"`\n\t// ExitErrHandler processes any error encountered while running a Command before it is\n\t// returned to the caller. If no function is provided, HandleExitCoder is used as the\n\t// default behavior.\n\tExitErrHandler ExitErrHandlerFunc `json:\"-\"`\n\t// Other custom info\n\tMetadata map[string]interface{} `json:\"metadata\"`\n\t// Carries a function which returns app specific info.\n\tExtraInfo func() map[string]string `json:\"-\"`\n\t// CustomRootCommandHelpTemplate the text template for app help topic.\n\t// cli.go uses text/template to render templates. You can\n\t// render custom help text by setting this variable.\n\tCustomRootCommandHelpTemplate string `json:\"-\"`\n\t// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is \",\"\n\tSliceFlagSeparator string `json:\"sliceFlagSeparator\"`\n\t// DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false\n\tDisableSliceFlagSeparator bool `json:\"disableSliceFlagSeparator\"`\n\t// MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is \"=\"\n\tMapFlagKeyValueSeparator string `json:\"mapFlagKeyValueSeparator\"`\n\t// Boolean to enable short-option handling so user can combine several\n\t// single-character bool arguments into one\n\t// i.e. foobar -o -v -> foobar -ov\n\tUseShortOptionHandling bool `json:\"useShortOptionHandling\"`\n\t// Enable suggestions for commands and flags\n\tSuggest bool `json:\"suggest\"`\n\t// Allows global flags set by libraries which use flag.XXXVar(...) directly\n\t// to be parsed through this library\n\tAllowExtFlags bool `json:\"allowExtFlags\"`\n\t// Treat all flags as normal arguments if true\n\tSkipFlagParsing bool `json:\"skipFlagParsing\"`\n\t// CustomHelpTemplate the text template for the command help topic.\n\t// cli.go uses text/template to render templates. You can\n\t// render custom help text by setting this variable.\n\tCustomHelpTemplate string `json:\"-\"`\n\t// Use longest prefix match for commands\n\tPrefixMatchCommands bool `json:\"prefixMatchCommands\"`\n\t// Custom suggest command for matching\n\tSuggestCommandFunc SuggestCommandFunc `json:\"-\"`\n\t// Flag exclusion group\n\tMutuallyExclusiveFlags []MutuallyExclusiveFlags `json:\"mutuallyExclusiveFlags\"`\n\t// Arguments to parse for this command\n\tArguments []Argument `json:\"arguments\"`\n\t// Whether to read arguments from stdin\n\t// applicable to root command only\n\tReadArgsFromStdin bool `json:\"readArgsFromStdin\"`\n\t// StopOnNthArg provides v2-like behavior for specific commands by stopping\n\t// flag parsing after N positional arguments are encountered. When set to N,\n\t// all remaining arguments after the Nth positional argument will be treated\n\t// as arguments, not flags.\n\t//\n\t// A value of 0 means all arguments are treated as positional (no flag parsing).\n\t// A nil value means normal v3 flag parsing behavior (flags can appear anywhere).\n\tStopOnNthArg *int `json:\"stopOnNthArg\"`\n\n\t// Has unexported fields.\n}\n    Command contains everything needed to run an application that accepts a\n    string slice of arguments such as os.Args. A given Command may contain Flags\n    and sub-commands in Commands.\n\nfunc (cmd *Command) Args() Args\n    Args returns the command line arguments associated with the command.\n\nfunc (cmd *Command) Bool(name string) bool\n\nfunc (cmd *Command) Command(name string) *Command\n\nfunc (cmd *Command) Count(name string) int\n    Count returns the num of occurrences of this flag\n\nfunc (cmd *Command) Duration(name string) time.Duration\n\nfunc (cmd *Command) FlagNames() []string\n    FlagNames returns a slice of flag names used by the this command and all of\n    its parent commands.\n\nfunc (cmd *Command) Float(name string) float64\n    Float looks up the value of a local FloatFlag, returns 0 if not found\n\nfunc (cmd *Command) Float32(name string) float32\n    Float32 looks up the value of a local Float32Flag, returns 0 if not found\n\nfunc (c *Command) Float32Arg(name string) float32\n\nfunc (c *Command) Float32Args(name string) []float32\n\nfunc (cmd *Command) Float32Slice(name string) []float32\n    Float32Slice looks up the value of a local Float32Slice, returns nil if not\n    found\n\nfunc (cmd *Command) Float64(name string) float64\n    Float64 looks up the value of a local Float64Flag, returns 0 if not found\n\nfunc (c *Command) Float64Arg(name string) float64\n\nfunc (c *Command) Float64Args(name string) []float64\n\nfunc (cmd *Command) Float64Slice(name string) []float64\n    Float64Slice looks up the value of a local Float64SliceFlag, returns nil if\n    not found\n\nfunc (c *Command) FloatArg(name string) float64\n\nfunc (c *Command) FloatArgs(name string) []float64\n\nfunc (cmd *Command) FloatSlice(name string) []float64\n    FloatSlice looks up the value of a local FloatSliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) FullName() string\n    FullName returns the full name of the command. For commands with parents\n    this ensures that the parent commands are part of the command path.\n\nfunc (cmd *Command) Generic(name string) Value\n    Generic looks up the value of a local GenericFlag, returns nil if not found\n\nfunc (cmd *Command) HasName(name string) bool\n    HasName returns true if Command.Name matches given name\n\nfunc (cmd *Command) Int(name string) int\n    Int looks up the value of a local Int64Flag, returns 0 if not found\n\nfunc (cmd *Command) Int16(name string) int16\n    Int16 looks up the value of a local Int16Flag, returns 0 if not found\n\nfunc (c *Command) Int16Arg(name string) int16\n\nfunc (c *Command) Int16Args(name string) []int16\n\nfunc (cmd *Command) Int16Slice(name string) []int16\n    Int16Slice looks up the value of a local Int16SliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Int32(name string) int32\n    Int32 looks up the value of a local Int32Flag, returns 0 if not found\n\nfunc (c *Command) Int32Arg(name string) int32\n\nfunc (c *Command) Int32Args(name string) []int32\n\nfunc (cmd *Command) Int32Slice(name string) []int32\n    Int32Slice looks up the value of a local Int32SliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Int64(name string) int64\n    Int64 looks up the value of a local Int64Flag, returns 0 if not found\n\nfunc (c *Command) Int64Arg(name string) int64\n\nfunc (c *Command) Int64Args(name string) []int64\n\nfunc (cmd *Command) Int64Slice(name string) []int64\n    Int64Slice looks up the value of a local Int64SliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Int8(name string) int8\n    Int8 looks up the value of a local Int8Flag, returns 0 if not found\n\nfunc (c *Command) Int8Arg(name string) int8\n\nfunc (c *Command) Int8Args(name string) []int8\n\nfunc (cmd *Command) Int8Slice(name string) []int8\n    Int8Slice looks up the value of a local Int8SliceFlag, returns nil if not\n    found\n\nfunc (c *Command) IntArg(name string) int\n\nfunc (c *Command) IntArgs(name string) []int\n\nfunc (cmd *Command) IntSlice(name string) []int\n    IntSlice looks up the value of a local IntSliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) IsSet(name string) bool\n    IsSet determines if the flag was actually set\n\nfunc (cmd *Command) Lineage() []*Command\n    Lineage returns *this* command and all of its ancestor commands in order\n    from child to parent\n\nfunc (cmd *Command) LocalFlagNames() []string\n    LocalFlagNames returns a slice of flag names used in this command.\n\nfunc (cmd *Command) NArg() int\n    NArg returns the number of the command line arguments.\n\nfunc (cmd *Command) Names() []string\n    Names returns the names including short names and aliases.\n\nfunc (cmd *Command) NumFlags() int\n    NumFlags returns the number of flags set\n\nfunc (cmd *Command) Root() *Command\n    Root returns the Command at the root of the graph\n\nfunc (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error)\n    Run is the entry point to the command graph. The positional arguments are\n    parsed according to the Flag and Command definitions and the matching Action\n    functions are run.\n\nfunc (cmd *Command) Set(name, value string) error\n    Set sets a context flag to a value.\n\nfunc (cmd *Command) String(name string) string\n\nfunc (c *Command) StringArg(name string) string\n\nfunc (c *Command) StringArgs(name string) []string\n\nfunc (cmd *Command) StringMap(name string) map[string]string\n    StringMap looks up the value of a local StringMapFlag, returns nil if not\n    found\n\nfunc (cmd *Command) StringSlice(name string) []string\n    StringSlice looks up the value of a local StringSliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Timestamp(name string) time.Time\n    Timestamp gets the timestamp from a flag name\n\nfunc (c *Command) TimestampArg(name string) time.Time\n\nfunc (c *Command) TimestampArgs(name string) []time.Time\n\nfunc (cmd *Command) ToFishCompletion() (string, error)\n    ToFishCompletion creates a fish completion string for the `*Command` The\n    function errors if either parsing or writing of the string fails.\n\nfunc (cmd *Command) Uint(name string) uint\n    Uint looks up the value of a local Uint64Flag, returns 0 if not found\n\nfunc (cmd *Command) Uint16(name string) uint16\n    Uint16 looks up the value of a local Uint16Flag, returns 0 if not found\n\nfunc (c *Command) Uint16Arg(name string) uint16\n\nfunc (c *Command) Uint16Args(name string) []uint16\n\nfunc (cmd *Command) Uint16Slice(name string) []uint16\n    Uint16Slice looks up the value of a local Uint16SliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Uint32(name string) uint32\n    Uint32 looks up the value of a local Uint32Flag, returns 0 if not found\n\nfunc (c *Command) Uint32Arg(name string) uint32\n\nfunc (c *Command) Uint32Args(name string) []uint32\n\nfunc (cmd *Command) Uint32Slice(name string) []uint32\n    Uint32Slice looks up the value of a local Uint32SliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Uint64(name string) uint64\n    Uint64 looks up the value of a local Uint64Flag, returns 0 if not found\n\nfunc (c *Command) Uint64Arg(name string) uint64\n\nfunc (c *Command) Uint64Args(name string) []uint64\n\nfunc (cmd *Command) Uint64Slice(name string) []uint64\n    Uint64Slice looks up the value of a local Uint64SliceFlag, returns nil if\n    not found\n\nfunc (cmd *Command) Uint8(name string) uint8\n    Uint8 looks up the value of a local Uint8Flag, returns 0 if not found\n\nfunc (c *Command) Uint8Arg(name string) uint8\n\nfunc (c *Command) Uint8Args(name string) []uint8\n\nfunc (cmd *Command) Uint8Slice(name string) []uint8\n    Uint8Slice looks up the value of a local Uint8SliceFlag, returns nil if not\n    found\n\nfunc (c *Command) UintArg(name string) uint\n\nfunc (c *Command) UintArgs(name string) []uint\n\nfunc (cmd *Command) UintSlice(name string) []uint\n    UintSlice looks up the value of a local UintSliceFlag, returns nil if not\n    found\n\nfunc (cmd *Command) Value(name string) interface{}\n    Value returns the value of the flag corresponding to `name`\n\nfunc (cmd *Command) VisibleCategories() []CommandCategory\n    VisibleCategories returns a slice of categories and commands that are\n    Hidden=false\n\nfunc (cmd *Command) VisibleCommands() []*Command\n    VisibleCommands returns a slice of the Commands with Hidden=false\n\nfunc (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory\n    VisibleFlagCategories returns a slice containing all the visible flag\n    categories with the flags they contain\n\nfunc (cmd *Command) VisibleFlags() []Flag\n    VisibleFlags returns a slice of the Flags with Hidden=false\n\nfunc (cmd *Command) VisiblePersistentFlags() []Flag\n    VisiblePersistentFlags returns a slice of LocalFlag with Persistent=true and\n    Hidden=false.\n\ntype CommandCategories interface {\n\t// AddCommand adds a command to a category, creating a new category if necessary.\n\tAddCommand(category string, command *Command)\n\t// Categories returns a slice of categories sorted by name\n\tCategories() []CommandCategory\n}\n    CommandCategories interface allows for category manipulation\n\ntype CommandCategory interface {\n\t// Name returns the category name string\n\tName() string\n\t// VisibleCommands returns a slice of the Commands with Hidden=false\n\tVisibleCommands() []*Command\n}\n    CommandCategory is a category containing commands.\n\ntype CommandNotFoundFunc func(context.Context, *Command, string)\n    CommandNotFoundFunc is executed if the proper command cannot be found\n\ntype ConfigureShellCompletionCommand func(*Command)\n    ConfigureShellCompletionCommand is a function to configure a shell\n    completion command\n\ntype Countable interface {\n\tCount() int\n}\n    Countable is an interface to enable detection of flag values which support\n    repetitive flags\n\ntype DocGenerationFlag interface {\n\t// TakesValue returns true if the flag takes a value, otherwise false\n\tTakesValue() bool\n\n\t// GetUsage returns the usage string for the flag\n\tGetUsage() string\n\n\t// GetValue returns the flags value as string representation and an empty\n\t// string if the flag takes no value at all.\n\tGetValue() string\n\n\t// GetDefaultText returns the default text for this flag\n\tGetDefaultText() string\n\n\t// GetEnvVars returns the env vars for this flag\n\tGetEnvVars() []string\n\n\t// IsDefaultVisible returns whether the default value should be shown in\n\t// help text\n\tIsDefaultVisible() bool\n\t// TypeName to detect if a flag is a string, bool, etc.\n\tTypeName() string\n}\n    DocGenerationFlag is an interface that allows documentation generation for\n    the flag\n\ntype DocGenerationMultiValueFlag interface {\n\tDocGenerationFlag\n\n\t// IsMultiValueFlag returns true for flags that can be given multiple times.\n\tIsMultiValueFlag() bool\n}\n    DocGenerationMultiValueFlag extends DocGenerationFlag for slice/map based\n    flags.\n\ntype DurationFlag = FlagBase[time.Duration, NoConfig, durationValue]\n\ntype EnvValueSource interface {\n\tIsFromEnv() bool\n\tKey() string\n}\n    EnvValueSource is to specifically detect env sources when printing help text\n\ntype ErrorFormatter interface {\n\tFormat(s fmt.State, verb rune)\n}\n    ErrorFormatter is the interface that will suitably format the error output\n\ntype ExitCoder interface {\n\terror\n\tExitCode() int\n}\n    ExitCoder is the interface checked by `Command` for a custom exit code.\n\nfunc Exit(message any, exitCode int) ExitCoder\n    Exit wraps a message and exit code into an error, which by default is\n    handled with a call to os.Exit during default error handling.\n\n    This is the simplest way to trigger a non-zero exit code for a Command\n    without having to call os.Exit manually. During testing, this behavior can\n    be avoided by overriding the ExitErrHandler function on a Command or the\n    package-global OsExiter function.\n\ntype ExitErrHandlerFunc func(context.Context, *Command, error)\n    ExitErrHandlerFunc is executed if provided in order to handle exitError\n    values returned by Actions and Before/After functions.\n\ntype Flag interface {\n\tfmt.Stringer\n\n\t// Retrieve the value of the Flag\n\tGet() any\n\n\t// Lifecycle methods.\n\t// flag callback prior to parsing\n\tPreParse() error\n\n\t// flag callback post parsing\n\tPostParse() error\n\n\t// Apply Flag settings to the given flag set\n\tSet(string, string) error\n\n\t// All possible names for this flag\n\tNames() []string\n\n\t// Whether the flag has been set or not\n\tIsSet() bool\n}\n    Flag is a common interface related to parsing flags in cli. For more\n    advanced flag parsing techniques, it is recommended that this interface be\n    implemented.\n\nvar GenerateShellCompletionFlag Flag = &BoolFlag{\n\tName:   \"generate-shell-completion\",\n\tHidden: true,\n}\n    GenerateShellCompletionFlag enables shell completion\n\nvar HelpFlag Flag = &BoolFlag{\n\tName:        \"help\",\n\tAliases:     []string{\"h\"},\n\tUsage:       \"show help\",\n\tHideDefault: true,\n\tLocal:       true,\n}\n    HelpFlag prints the help for all commands and subcommands. Set to nil to\n    disable the flag. The subcommand will still be added unless HideHelp or\n    HideHelpCommand is set to true.\n\nvar VersionFlag Flag = &BoolFlag{\n\tName:        \"version\",\n\tAliases:     []string{\"v\"},\n\tUsage:       \"print the version\",\n\tHideDefault: true,\n\tLocal:       true,\n}\n    VersionFlag prints the version for the application\n\ntype FlagBase[T any, C any, VC ValueCreator[T, C]] struct {\n\tName             string                                   `json:\"name\"`             // name of the flag\n\tCategory         string                                   `json:\"category\"`         // category of the flag, if any\n\tDefaultText      string                                   `json:\"defaultText\"`      // default text of the flag for usage purposes\n\tHideDefault      bool                                     `json:\"hideDefault\"`      // whether to hide the default value in output\n\tUsage            string                                   `json:\"usage\"`            // usage string for help output\n\tSources          ValueSourceChain                         `json:\"-\"`                // sources to load flag value from\n\tRequired         bool                                     `json:\"required\"`         // whether the flag is required or not\n\tHidden           bool                                     `json:\"hidden\"`           // whether to hide the flag in help output\n\tLocal            bool                                     `json:\"local\"`            // whether the flag needs to be applied to subcommands as well\n\tValue            T                                        `json:\"defaultValue\"`     // default value for this flag if not set by from any source\n\tDestination      *T                                       `json:\"-\"`                // destination pointer for value when set\n\tAliases          []string                                 `json:\"aliases\"`          // Aliases that are allowed for this flag\n\tTakesFile        bool                                     `json:\"takesFileArg\"`     // whether this flag takes a file argument, mainly for shell completion purposes\n\tAction           func(context.Context, *Command, T) error `json:\"-\"`                // Action callback to be called when flag is set\n\tConfig           C                                        `json:\"config\"`           // Additional/Custom configuration associated with this flag type\n\tOnlyOnce         bool                                     `json:\"onlyOnce\"`         // whether this flag can be duplicated on the command line\n\tValidator        func(T) error                            `json:\"-\"`                // custom function to validate this flag value\n\tValidateDefaults bool                                     `json:\"validateDefaults\"` // whether to validate defaults or not\n\n\t// Has unexported fields.\n}\n    FlagBase [T,C,VC] is a generic flag base which can be used as a boilerplate\n    to implement the most common interfaces used by urfave/cli.\n\n        T specifies the type\n        C specifies the configuration required(if any for that flag type)\n        VC specifies the value creator which creates the flag.Value emulation\n\nfunc (f *FlagBase[T, C, VC]) Count() int\n    Count returns the number of times this flag has been invoked\n\nfunc (f *FlagBase[T, C, V]) Get() any\n\nfunc (f *FlagBase[T, C, V]) GetCategory() string\n    GetCategory returns the category of the flag\n\nfunc (f *FlagBase[T, C, V]) GetDefaultText() string\n    GetDefaultText returns the default text for this flag\n\nfunc (f *FlagBase[T, C, V]) GetEnvVars() []string\n    GetEnvVars returns the env vars for this flag\n\nfunc (f *FlagBase[T, C, V]) GetUsage() string\n    GetUsage returns the usage string for the flag\n\nfunc (f *FlagBase[T, C, V]) GetValue() string\n    GetValue returns the flags value as string representation and an empty\n    string if the flag takes no value at all.\n\nfunc (f *FlagBase[T, C, VC]) IsBoolFlag() bool\n    IsBoolFlag returns whether the flag doesnt need to accept args\n\nfunc (f *FlagBase[T, C, V]) IsDefaultVisible() bool\n    IsDefaultVisible returns true if the flag is not hidden, otherwise false\n\nfunc (f *FlagBase[T, C, VC]) IsLocal() bool\n    IsLocal returns false if flag needs to be persistent across subcommands\n\nfunc (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool\n    IsMultiValueFlag returns true if the value type T can take multiple values\n    from cmd line. This is true for slice and map type flags\n\nfunc (f *FlagBase[T, C, V]) IsRequired() bool\n    IsRequired returns whether or not the flag is required\n\nfunc (f *FlagBase[T, C, V]) IsSet() bool\n    IsSet returns whether or not the flag has been set through env or file\n\nfunc (f *FlagBase[T, C, V]) IsVisible() bool\n    IsVisible returns true if the flag is not hidden, otherwise false\n\nfunc (f *FlagBase[T, C, V]) Names() []string\n    Names returns the names of the flag\n\nfunc (f *FlagBase[T, C, V]) PostParse() error\n    PostParse populates the flag given the flag set and environment\n\nfunc (f *FlagBase[T, C, V]) PreParse() error\n\nfunc (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error\n    RunAction executes flag action if set\n\nfunc (f *FlagBase[T, C, V]) Set(_ string, val string) error\n    Set applies given value from string\n\nfunc (f *FlagBase[T, C, V]) SetCategory(c string)\n\nfunc (f *FlagBase[T, C, V]) String() string\n    String returns a readable representation of this value (for usage defaults)\n\nfunc (f *FlagBase[T, C, V]) TakesValue() bool\n    TakesValue returns true if the flag takes a value, otherwise false\n\nfunc (f *FlagBase[T, C, V]) TypeName() string\n    TypeName returns the type of the flag.\n\ntype FlagCategories interface {\n\t// AddFlags adds a flag to a category, creating a new category if necessary.\n\tAddFlag(category string, fl Flag)\n\t// VisibleCategories returns a slice of visible flag categories sorted by name\n\tVisibleCategories() []VisibleFlagCategory\n}\n    FlagCategories interface allows for category manipulation\n\ntype FlagEnvHintFunc func(envVars []string, str string) string\n    FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help\n    with the environment variable details.\n\nvar FlagEnvHinter FlagEnvHintFunc = withEnvHint\n    FlagEnvHinter annotates flag help message with the environment variable\n    details. This is used by the default FlagStringer.\n\ntype FlagFileHintFunc func(filePath, str string) string\n    FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help\n    with the file path details.\n\nvar FlagFileHinter FlagFileHintFunc = withFileHint\n    FlagFileHinter annotates flag help message with the environment variable\n    details. This is used by the default FlagStringer.\n\ntype FlagNamePrefixFunc func(fullName []string, placeholder string) string\n    FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix\n    text for a flag's full name.\n\nvar FlagNamePrefixer FlagNamePrefixFunc = prefixedNames\n    FlagNamePrefixer converts a full flag name and its placeholder into the help\n    message flag prefix. This is used by the default FlagStringer.\n\ntype FlagStringFunc func(Flag) string\n    FlagStringFunc is used by the help generation to display a flag, which is\n    expected to be a single line.\n\nvar FlagStringer FlagStringFunc = stringifyFlag\n    FlagStringer converts a flag definition to a string. This is used by help to\n    display a flag.\n\ntype FlagsByName []Flag\n    FlagsByName is a slice of Flag.\n\nfunc (f FlagsByName) Len() int\n\nfunc (f FlagsByName) Less(i, j int) bool\n\nfunc (f FlagsByName) Swap(i, j int)\n\ntype Float32Arg = ArgumentBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32Args = ArgumentsBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32Flag = FlagBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32Slice = SliceBase[float32, NoConfig, floatValue[float32]]\n\ntype Float32SliceFlag = FlagBase[[]float32, NoConfig, Float32Slice]\n\ntype Float64Arg = ArgumentBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64Args = ArgumentsBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64Flag = FlagBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64Slice = SliceBase[float64, NoConfig, floatValue[float64]]\n\ntype Float64SliceFlag = FlagBase[[]float64, NoConfig, Float64Slice]\n\ntype FloatArg = ArgumentBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatArgs = ArgumentsBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatFlag = FlagBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatSlice = SliceBase[float64, NoConfig, floatValue[float64]]\n\ntype FloatSliceFlag = FlagBase[[]float64, NoConfig, FloatSlice]\n\ntype GenericFlag = FlagBase[Value, NoConfig, genericValue]\n\ntype HelpPrinterCustomFunc func(w io.Writer, templ string, data any, customFunc map[string]any)\n    Prints help for the Command with custom template function.\n\nvar HelpPrinterCustom HelpPrinterCustomFunc = DefaultPrintHelpCustom\n    HelpPrinterCustom is a function that writes the help output. It is used as\n    the default implementation of HelpPrinter, and may be called directly if the\n    ExtraInfo field is set on a Command.\n\n    In the default implementation, if the customFuncs argument contains a\n    \"wrapAt\" key, which is a function which takes no arguments and returns an\n    int, this int value will be used to produce a \"wrap\" function used by the\n    default template to wrap long lines.\n\ntype HelpPrinterFunc func(w io.Writer, templ string, data any)\n    HelpPrinterFunc prints help for the Command.\n\nvar HelpPrinter HelpPrinterFunc = DefaultPrintHelp\n    HelpPrinter is a function that writes the help output. If not set\n    explicitly, this calls HelpPrinterCustom using only the default template\n    functions.\n\n    If custom logic for printing help is required, this function can be\n    overridden. If the ExtraInfo field is defined on a Command, this function\n    should not be modified, as HelpPrinterCustom will be used directly in order\n    to capture the extra information.\n\ntype Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16Args = ArgumentsBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16Flag = FlagBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16Slice = SliceBase[int16, IntegerConfig, intValue[int16]]\n\ntype Int16SliceFlag = FlagBase[[]int16, IntegerConfig, Int16Slice]\n\ntype Int32Arg = ArgumentBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32Args = ArgumentsBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32Flag = FlagBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32Slice = SliceBase[int32, IntegerConfig, intValue[int32]]\n\ntype Int32SliceFlag = FlagBase[[]int32, IntegerConfig, Int32Slice]\n\ntype Int64Arg = ArgumentBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64Args = ArgumentsBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64Flag = FlagBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64Slice = SliceBase[int64, IntegerConfig, intValue[int64]]\n\ntype Int64SliceFlag = FlagBase[[]int64, IntegerConfig, Int64Slice]\n\ntype Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8Args = ArgumentsBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8Flag = FlagBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8Slice = SliceBase[int8, IntegerConfig, intValue[int8]]\n\ntype Int8SliceFlag = FlagBase[[]int8, IntegerConfig, Int8Slice]\n\ntype IntArg = ArgumentBase[int, IntegerConfig, intValue[int]]\n\ntype IntArgs = ArgumentsBase[int, IntegerConfig, intValue[int]]\n\ntype IntFlag = FlagBase[int, IntegerConfig, intValue[int]]\n\ntype IntSlice = SliceBase[int, IntegerConfig, intValue[int]]\n\ntype IntSliceFlag = FlagBase[[]int, IntegerConfig, IntSlice]\n\ntype IntegerConfig struct {\n\tBase int\n}\n    IntegerConfig is the configuration for all integer type flags\n\ntype InvalidFlagAccessFunc func(context.Context, *Command, string)\n    InvalidFlagAccessFunc is executed when an invalid flag is accessed from the\n    context.\n\ntype LocalFlag interface {\n\tIsLocal() bool\n}\n    LocalFlag is an interface to enable detection of flags which are local to\n    current command\n\ntype MapBase[T any, C any, VC ValueCreator[T, C]] struct {\n\t// Has unexported fields.\n}\n    MapBase wraps map[string]T to satisfy flag.Value\n\nfunc NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string]T) *MapBase[T, C, VC]\n    NewMapBase makes a *MapBase with default values\n\nfunc (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value\n\nfunc (i *MapBase[T, C, VC]) Get() interface{}\n    Get returns the mapping of values set by this flag\n\nfunc (i *MapBase[T, C, VC]) Serialize() string\n    Serialize allows MapBase to fulfill Serializer\n\nfunc (i *MapBase[T, C, VC]) Set(value string) error\n    Set parses the value and appends it to the list of values\n\nfunc (i *MapBase[T, C, VC]) String() string\n    String returns a readable representation of this value (for usage defaults)\n\nfunc (i MapBase[T, C, VC]) ToString(t map[string]T) string\n\nfunc (i *MapBase[T, C, VC]) Value() map[string]T\n    Value returns the mapping of values set by this flag\n\ntype MapSource interface {\n\tfmt.Stringer\n\tfmt.GoStringer\n\n\t// Lookup returns the value from the source based on key\n\t// and if it was found\n\t// or returns an empty string and false\n\tLookup(string) (any, bool)\n}\n    MapSource is a source which can be used to look up a value based on a key\n    typically for use with a cli.Flag\n\nfunc NewMapSource(name string, m map[any]any) MapSource\n\ntype MultiError interface {\n\terror\n\tErrors() []error\n}\n    MultiError is an error that wraps multiple errors.\n\ntype MutuallyExclusiveFlags struct {\n\t// Flag list\n\tFlags [][]Flag\n\n\t// whether this group is required\n\tRequired bool\n\n\t// Category to apply to all flags within group\n\tCategory string\n}\n    MutuallyExclusiveFlags defines a mutually exclusive flag group Multiple\n    option paths can be provided out of which only one can be defined on cmdline\n    So for example [ --foo | [ --bar something --darth somethingelse ] ]\n\ntype NoConfig struct{}\n    NoConfig is for flags which dont need a custom configuration\n\ntype OnUsageErrorFunc func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error\n    OnUsageErrorFunc is executed if a usage error occurs. This is useful for\n    displaying customized usage error messages. This function is able to replace\n    the original error messages. If this function is not set, the \"Incorrect\n    usage\" is displayed and the execution is interrupted.\n\ntype RequiredFlag interface {\n\t// whether the flag is a required flag or not\n\tIsRequired() bool\n}\n    RequiredFlag is an interface that allows us to mark flags as required\n    it allows flags required flags to be backwards compatible with the Flag\n    interface\n\ntype Serializer interface {\n\tSerialize() string\n}\n    Serializer is used to circumvent the limitations of flag.FlagSet.Set\n\ntype ShellCompleteFunc func(context.Context, *Command)\n    ShellCompleteFunc is an action to execute when the shell completion flag is\n    set\n\ntype SliceBase[T any, C any, VC ValueCreator[T, C]] struct {\n\t// Has unexported fields.\n}\n    SliceBase wraps []T to satisfy flag.Value\n\nfunc NewSliceBase[T any, C any, VC ValueCreator[T, C]](defaults ...T) *SliceBase[T, C, VC]\n    NewSliceBase makes a *SliceBase with default values\n\nfunc (i SliceBase[T, C, VC]) Create(val []T, p *[]T, c C) Value\n\nfunc (i *SliceBase[T, C, VC]) Get() interface{}\n    Get returns the slice of values set by this flag\n\nfunc (i *SliceBase[T, C, VC]) Serialize() string\n    Serialize allows SliceBase to fulfill Serializer\n\nfunc (i *SliceBase[T, C, VC]) Set(value string) error\n    Set parses the value and appends it to the list of values\n\nfunc (i *SliceBase[T, C, VC]) String() string\n    String returns a readable representation of this value (for usage defaults)\n\nfunc (i SliceBase[T, C, VC]) ToString(t []T) string\n\nfunc (i *SliceBase[T, C, VC]) Value() []T\n    Value returns the slice of values set by this flag\n\ntype StringArg = ArgumentBase[string, StringConfig, stringValue]\n\ntype StringArgs = ArgumentsBase[string, StringConfig, stringValue]\n\ntype StringConfig struct {\n\t// Whether to trim whitespace of parsed value\n\tTrimSpace bool\n}\n    StringConfig defines the configuration for string flags\n\ntype StringFlag = FlagBase[string, StringConfig, stringValue]\n\ntype StringMap = MapBase[string, StringConfig, stringValue]\n\ntype StringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap]\n\ntype StringMapFlag = FlagBase[map[string]string, StringConfig, StringMap]\n\ntype StringSlice = SliceBase[string, StringConfig, stringValue]\n\ntype StringSliceFlag = FlagBase[[]string, StringConfig, StringSlice]\n\ntype SuggestCommandFunc func(commands []*Command, provided string) string\n\ntype SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string\n\ntype TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue]\n\ntype TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue]\n\ntype TimestampConfig struct {\n\tTimezone *time.Location\n\t// Available layouts for flag value.\n\t//\n\t// Note that value for formats with missing year/date will be interpreted as current year/date respectively.\n\t//\n\t// Read more about time layouts: https://pkg.go.dev/time#pkg-constants\n\tLayouts []string\n}\n    TimestampConfig defines the config for timestamp flags\n\ntype TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampValue]\n\ntype Uint16Arg = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16Args = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16Flag = FlagBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16Slice = SliceBase[uint16, IntegerConfig, uintValue[uint16]]\n\ntype Uint16SliceFlag = FlagBase[[]uint16, IntegerConfig, Uint16Slice]\n\ntype Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32Args = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32Flag = FlagBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32Slice = SliceBase[uint32, IntegerConfig, uintValue[uint32]]\n\ntype Uint32SliceFlag = FlagBase[[]uint32, IntegerConfig, Uint32Slice]\n\ntype Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64Args = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64Flag = FlagBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64Slice = SliceBase[uint64, IntegerConfig, uintValue[uint64]]\n\ntype Uint64SliceFlag = FlagBase[[]uint64, IntegerConfig, Uint64Slice]\n\ntype Uint8Arg = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8Args = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8Flag = FlagBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8Slice = SliceBase[uint8, IntegerConfig, uintValue[uint8]]\n\ntype Uint8SliceFlag = FlagBase[[]uint8, IntegerConfig, Uint8Slice]\n\ntype UintArg = ArgumentBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintArgs = ArgumentsBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintFlag = FlagBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintSlice = SliceBase[uint, IntegerConfig, uintValue[uint]]\n\ntype UintSliceFlag = FlagBase[[]uint, IntegerConfig, UintSlice]\n\ntype Value interface {\n\tflag.Value\n\tflag.Getter\n}\n    Value represents a value as used by cli. For now it implements the golang\n    flag.Value interface\n\ntype ValueCreator[T any, C any] interface {\n\tCreate(T, *T, C) Value\n\tToString(T) string\n}\n    ValueCreator is responsible for creating a flag.Value emulation as well as\n    custom formatting\n\n        T specifies the type\n        C specifies the config for the type\n\ntype ValueSource interface {\n\tfmt.Stringer\n\tfmt.GoStringer\n\n\t// Lookup returns the value from the source and if it was found\n\t// or returns an empty string and false\n\tLookup() (string, bool)\n}\n    ValueSource is a source which can be used to look up a value, typically for\n    use with a cli.Flag\n\nfunc EnvVar(key string) ValueSource\n\nfunc File(path string) ValueSource\n\nfunc NewMapValueSource(key string, ms MapSource) ValueSource\n\ntype ValueSourceChain struct {\n\tChain []ValueSource\n}\n    ValueSourceChain contains an ordered series of ValueSource that allows for\n    lookup where the first ValueSource to resolve is returned\n\nfunc EnvVars(keys ...string) ValueSourceChain\n    EnvVars is a helper function to encapsulate a number of envVarValueSource\n    together as a ValueSourceChain\n\nfunc Files(paths ...string) ValueSourceChain\n    Files is a helper function to encapsulate a number of fileValueSource\n    together as a ValueSourceChain\n\nfunc NewValueSourceChain(src ...ValueSource) ValueSourceChain\n\nfunc (vsc *ValueSourceChain) Append(other ValueSourceChain)\n\nfunc (vsc *ValueSourceChain) EnvKeys() []string\n\nfunc (vsc *ValueSourceChain) GoString() string\n\nfunc (vsc *ValueSourceChain) Lookup() (string, bool)\n\nfunc (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool)\n\nfunc (vsc *ValueSourceChain) String() string\n\ntype VisibleFlag interface {\n\t// IsVisible returns true if the flag is not hidden, otherwise false\n\tIsVisible() bool\n}\n    VisibleFlag is an interface that allows to check if a flag is visible\n\ntype VisibleFlagCategory interface {\n\t// Name returns the category name string\n\tName() string\n\t// Flags returns a slice of VisibleFlag sorted by name\n\tFlags() []Flag\n}\n    VisibleFlagCategory is a category containing flags.\n\n"
  },
  {
    "path": "value_source.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\n// ValueSource is a source which can be used to look up a value,\n// typically for use with a cli.Flag\ntype ValueSource interface {\n\tfmt.Stringer\n\tfmt.GoStringer\n\n\t// Lookup returns the value from the source and if it was found\n\t// or returns an empty string and false\n\tLookup() (string, bool)\n}\n\n// EnvValueSource is to specifically detect env sources when\n// printing help text\ntype EnvValueSource interface {\n\tIsFromEnv() bool\n\tKey() string\n}\n\n// MapSource is a source which can be used to look up a value\n// based on a key\n// typically for use with a cli.Flag\ntype MapSource interface {\n\tfmt.Stringer\n\tfmt.GoStringer\n\n\t// Lookup returns the value from the source based on key\n\t// and if it was found\n\t// or returns an empty string and false\n\tLookup(string) (any, bool)\n}\n\n// ValueSourceChain contains an ordered series of ValueSource that\n// allows for lookup where the first ValueSource to resolve is\n// returned\ntype ValueSourceChain struct {\n\tChain []ValueSource\n}\n\nfunc NewValueSourceChain(src ...ValueSource) ValueSourceChain {\n\treturn ValueSourceChain{\n\t\tChain: src,\n\t}\n}\n\nfunc (vsc *ValueSourceChain) Append(other ValueSourceChain) {\n\tvsc.Chain = append(vsc.Chain, other.Chain...)\n}\n\nfunc (vsc *ValueSourceChain) EnvKeys() []string {\n\tvals := []string{}\n\n\tfor _, src := range vsc.Chain {\n\t\tif v, ok := src.(EnvValueSource); ok && v.IsFromEnv() {\n\t\t\tvals = append(vals, v.Key())\n\t\t}\n\t}\n\n\treturn vals\n}\n\nfunc (vsc *ValueSourceChain) String() string {\n\ts := []string{}\n\n\tfor _, vs := range vsc.Chain {\n\t\ts = append(s, vs.String())\n\t}\n\n\treturn strings.Join(s, \",\")\n}\n\nfunc (vsc *ValueSourceChain) GoString() string {\n\ts := []string{}\n\n\tfor _, vs := range vsc.Chain {\n\t\ts = append(s, vs.GoString())\n\t}\n\n\treturn fmt.Sprintf(\"&ValueSourceChain{Chain:{%[1]s}}\", strings.Join(s, \",\"))\n}\n\nfunc (vsc *ValueSourceChain) Lookup() (string, bool) {\n\ts, _, ok := vsc.LookupWithSource()\n\treturn s, ok\n}\n\nfunc (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool) {\n\tfor _, src := range vsc.Chain {\n\t\tif value, found := src.Lookup(); found {\n\t\t\treturn value, src, true\n\t\t}\n\t}\n\n\treturn \"\", nil, false\n}\n\n// envVarValueSource encapsulates a ValueSource from an environment variable\ntype envVarValueSource struct {\n\tkey string\n}\n\nfunc (e *envVarValueSource) Lookup() (string, bool) {\n\treturn os.LookupEnv(strings.TrimSpace(string(e.key)))\n}\n\nfunc (e *envVarValueSource) IsFromEnv() bool {\n\treturn true\n}\n\nfunc (e *envVarValueSource) Key() string {\n\treturn e.key\n}\n\nfunc (e *envVarValueSource) String() string { return fmt.Sprintf(\"environment variable %[1]q\", e.key) }\nfunc (e *envVarValueSource) GoString() string {\n\treturn fmt.Sprintf(\"&envVarValueSource{Key:%[1]q}\", e.key)\n}\n\nfunc EnvVar(key string) ValueSource {\n\treturn &envVarValueSource{\n\t\tkey: key,\n\t}\n}\n\n// EnvVars is a helper function to encapsulate a number of\n// envVarValueSource together as a ValueSourceChain\nfunc EnvVars(keys ...string) ValueSourceChain {\n\tvsc := ValueSourceChain{Chain: []ValueSource{}}\n\n\tfor _, key := range keys {\n\t\tvsc.Chain = append(vsc.Chain, EnvVar(key))\n\t}\n\n\treturn vsc\n}\n\n// fileValueSource encapsulates a ValueSource from a file\ntype fileValueSource struct {\n\tPath string\n}\n\nfunc (f *fileValueSource) Lookup() (string, bool) {\n\tdata, err := os.ReadFile(f.Path)\n\treturn string(data), err == nil\n}\n\nfunc (f *fileValueSource) String() string { return fmt.Sprintf(\"file %[1]q\", f.Path) }\nfunc (f *fileValueSource) GoString() string {\n\treturn fmt.Sprintf(\"&fileValueSource{Path:%[1]q}\", f.Path)\n}\n\nfunc File(path string) ValueSource {\n\treturn &fileValueSource{Path: path}\n}\n\n// Files is a helper function to encapsulate a number of\n// fileValueSource together as a ValueSourceChain\nfunc Files(paths ...string) ValueSourceChain {\n\tvsc := ValueSourceChain{Chain: []ValueSource{}}\n\n\tfor _, path := range paths {\n\t\tvsc.Chain = append(vsc.Chain, File(path))\n\t}\n\n\treturn vsc\n}\n\ntype mapSource struct {\n\tname string\n\tm    map[any]any\n}\n\nfunc NewMapSource(name string, m map[any]any) MapSource {\n\treturn &mapSource{\n\t\tname: name,\n\t\tm:    m,\n\t}\n}\n\nfunc (ms *mapSource) String() string { return fmt.Sprintf(\"map source %[1]q\", ms.name) }\nfunc (ms *mapSource) GoString() string {\n\treturn fmt.Sprintf(\"&mapSource{name:%[1]q}\", ms.name)\n}\n\n// Lookup returns a value from the map source. The lookup name may be a dot-separated path into the map.\n// If that is the case, it will recursively traverse the map based on the '.' delimited sections to find\n// a nested value for the key.\nfunc (ms *mapSource) Lookup(name string) (any, bool) {\n\tsections := strings.Split(name, \".\")\n\tif name == \"\" || len(sections) == 0 {\n\t\treturn nil, false\n\t}\n\n\tnode := ms.m\n\n\t// traverse into the map based on the dot-separated sections\n\tif len(sections) >= 2 { // the last section is the value we want, we will return it directly at the end\n\t\tfor _, section := range sections[:len(sections)-1] {\n\t\t\tchild, ok := node[section]\n\t\t\tif !ok {\n\t\t\t\treturn nil, false\n\t\t\t}\n\n\t\t\tswitch child := child.(type) {\n\t\t\tcase map[string]any:\n\t\t\t\tnode = make(map[any]any, len(child))\n\t\t\t\tfor k, v := range child {\n\t\t\t\t\tnode[k] = v\n\t\t\t\t}\n\t\t\tcase map[any]any:\n\t\t\t\tnode = child\n\t\t\tdefault:\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\t}\n\t}\n\n\tif val, ok := node[sections[len(sections)-1]]; ok {\n\t\treturn val, true\n\t}\n\treturn nil, false\n}\n\ntype mapValueSource struct {\n\tkey string\n\tms  MapSource\n}\n\nfunc NewMapValueSource(key string, ms MapSource) ValueSource {\n\treturn &mapValueSource{\n\t\tkey: key,\n\t\tms:  ms,\n\t}\n}\n\nfunc (mvs *mapValueSource) String() string {\n\treturn fmt.Sprintf(\"key %[1]q from %[2]s\", mvs.key, mvs.ms.String())\n}\n\nfunc (mvs *mapValueSource) GoString() string {\n\treturn fmt.Sprintf(\"&mapValueSource{key:%[1]q, src:%[2]s}\", mvs.key, mvs.ms.GoString())\n}\n\nfunc (mvs *mapValueSource) Lookup() (string, bool) {\n\tif v, ok := mvs.ms.Lookup(mvs.key); !ok {\n\t\treturn \"\", false\n\t} else {\n\t\treturn fmt.Sprintf(\"%+v\", v), true\n\t}\n}\n"
  },
  {
    "path": "value_source_test.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestZeroValueSourceChain(t *testing.T) {\n\tvar vc ValueSourceChain\n\tassert.Empty(t, vc.EnvKeys())\n\tassert.NotEmpty(t, vc.GoString())\n\tassert.Empty(t, vc.Chain)\n\tassert.Empty(t, vc.String())\n}\n\nfunc TestEnvVarValueSource(t *testing.T) {\n\tt.Run(\"implements ValueSource\", func(t *testing.T) {\n\t\tsrc := EnvVar(\"foo\")\n\t\trequire.Implements(t, (*ValueSource)(nil), src)\n\n\t\tt.Run(\"not found\", func(t *testing.T) {\n\t\t\tt.Setenv(\"foo\", \"bar\")\n\n\t\t\tsrc := EnvVar(\"foo_1\")\n\t\t\t_, ok := src.Lookup()\n\t\t\trequire.False(t, ok)\n\t\t})\n\n\t\tt.Run(\"found\", func(t *testing.T) {\n\t\t\tt.Setenv(\"foo\", \"bar\")\n\n\t\t\tr := require.New(t)\n\t\t\tsrc := EnvVar(\"foo\")\n\n\t\t\tstr, ok := src.Lookup()\n\t\t\tr.True(ok)\n\t\t\tr.Equal(str, \"bar\")\n\t\t})\n\t})\n\n\tt.Run(\"implements fmt.Stringer\", func(t *testing.T) {\n\t\tsrc := EnvVar(\"foo\")\n\t\tr := require.New(t)\n\n\t\tr.Implements((*fmt.Stringer)(nil), src)\n\t\tr.Equal(\"environment variable \\\"foo\\\"\", src.String())\n\t})\n\n\tt.Run(\"implements fmt.GoStringer\", func(t *testing.T) {\n\t\tsrc := EnvVar(\"foo\")\n\t\tr := require.New(t)\n\n\t\tr.Implements((*fmt.GoStringer)(nil), src)\n\t\tr.Equal(\"&envVarValueSource{Key:\\\"foo\\\"}\", src.GoString())\n\t})\n}\n\nfunc TestEnvVars(t *testing.T) {\n\tt.Setenv(\"myfoo\", \"mybar\")\n\n\tsource := EnvVars(\"foo1\", \"myfoo\")\n\tstr, src, ok := source.LookupWithSource()\n\n\tr := require.New(t)\n\tr.True(ok)\n\tr.Equal(str, \"mybar\")\n\tr.Contains(src.String(), \"\\\"myfoo\\\"\")\n}\n\nfunc TestFileValueSource(t *testing.T) {\n\tt.Run(\"implements ValueSource\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\tr.Implements((*ValueSource)(nil), &fileValueSource{})\n\n\t\tt.Run(\"not found\", func(t *testing.T) {\n\t\t\tsrc := File(fmt.Sprintf(\"junk_file_name-%[1]v\", rand.Int()))\n\t\t\t_, ok := src.Lookup()\n\t\t\tr.False(ok)\n\t\t})\n\n\t\tfileName := filepath.Join(os.TempDir(), fmt.Sprintf(\"urfave-cli-testing-existing_file-%[1]v\", rand.Int()))\n\t\tt.Cleanup(func() { _ = os.Remove(fileName) })\n\n\t\tr.Nil(os.WriteFile(fileName, []byte(\"pita\"), 0o644))\n\n\t\tt.Run(\"found\", func(t *testing.T) {\n\t\t\tsrc := File(fileName)\n\t\t\tstr, ok := src.Lookup()\n\t\t\tr.True(ok)\n\t\t\tr.Equal(\"pita\", str)\n\t\t})\n\t})\n\n\tt.Run(\"implements fmt.Stringer\", func(t *testing.T) {\n\t\tsrc := File(\"/dev/null\")\n\t\tr := require.New(t)\n\n\t\tr.Implements((*ValueSource)(nil), src)\n\t\tr.Equal(\"file \\\"/dev/null\\\"\", src.String())\n\t})\n\n\tt.Run(\"implements fmt.GoStringer\", func(t *testing.T) {\n\t\tsrc := File(\"/dev/null\")\n\t\tr := require.New(t)\n\n\t\tr.Implements((*ValueSource)(nil), src)\n\t\tr.Equal(\"&fileValueSource{Path:\\\"/dev/null\\\"}\", src.GoString())\n\t})\n}\n\nfunc TestFilePaths(t *testing.T) {\n\tr := require.New(t)\n\n\tfileName := filepath.Join(os.TempDir(), fmt.Sprintf(\"urfave-cli-tests-some_file_name_%[1]v\", rand.Int()))\n\tt.Cleanup(func() { _ = os.Remove(fileName) })\n\n\tr.Nil(os.WriteFile(fileName, []byte(\"Hello\"), 0o644))\n\n\tsources := Files(\"junk_file_name\", fileName)\n\tstr, src, ok := sources.LookupWithSource()\n\tr.True(ok)\n\tr.Equal(str, \"Hello\")\n\tr.Contains(src.String(), fmt.Sprintf(\"%[1]q\", fileName))\n}\n\nfunc TestValueSourceChainEnvKeys(t *testing.T) {\n\tchain := NewValueSourceChain(\n\t\t&staticValueSource{\"hello\"},\n\t)\n\tchain.Append(EnvVars(\"foo\", \"bar\"))\n\n\tr := require.New(t)\n\tr.Equal([]string{\"foo\", \"bar\"}, chain.EnvKeys())\n}\n\nfunc TestValueSourceChain(t *testing.T) {\n\tt.Run(\"implements ValueSource\", func(t *testing.T) {\n\t\tvsc := &ValueSourceChain{}\n\t\tr := require.New(t)\n\n\t\tr.Implements((*ValueSource)(nil), vsc)\n\n\t\t_, ok := vsc.Lookup()\n\t\tr.False(ok)\n\t})\n\n\tt.Run(\"implements fmt.GoStringer\", func(t *testing.T) {\n\t\tvsc := &ValueSourceChain{}\n\t\tr := require.New(t)\n\n\t\tr.Implements((*fmt.GoStringer)(nil), vsc)\n\t\tr.Equal(\"&ValueSourceChain{Chain:{}}\", vsc.GoString())\n\n\t\tvsc1 := NewValueSourceChain(&staticValueSource{v: \"yahtzee\"},\n\t\t\t&staticValueSource{v: \"matzoh\"},\n\t\t)\n\t\tr.Equal(\"&ValueSourceChain{Chain:{&staticValueSource{v:\\\"yahtzee\\\"},&staticValueSource{v:\\\"matzoh\\\"}}}\", vsc1.GoString())\n\t})\n\n\tt.Run(\"implements fmt.Stringer\", func(t *testing.T) {\n\t\tvsc := &ValueSourceChain{}\n\t\tr := require.New(t)\n\n\t\tr.Implements((*fmt.Stringer)(nil), vsc)\n\t\tr.Equal(\"\", vsc.String())\n\n\t\tvsc1 := NewValueSourceChain(\n\t\t\t&staticValueSource{v: \"soup\"},\n\t\t\t&staticValueSource{v: \"salad\"},\n\t\t\t&staticValueSource{v: \"pumpkins\"},\n\t\t)\n\t\tr.Equal(\"soup,salad,pumpkins\", vsc1.String())\n\t})\n}\n\ntype staticValueSource struct {\n\tv string\n}\n\nfunc (svs *staticValueSource) GoString() string {\n\treturn fmt.Sprintf(\"&staticValueSource{v:%[1]q}\", svs.v)\n}\nfunc (svs *staticValueSource) String() string         { return svs.v }\nfunc (svs *staticValueSource) Lookup() (string, bool) { return svs.v, true }\n\nfunc TestMapValueSource(t *testing.T) {\n\ttests := []struct {\n\t\tname  string\n\t\tm     map[any]any\n\t\tkey   string\n\t\tval   string\n\t\tfound bool\n\t}{\n\t\t{\n\t\t\tname: \"No map no key\",\n\t\t},\n\t\t{\n\t\t\tname: \"No map with key\",\n\t\t\tkey:  \"foo\",\n\t\t},\n\t\t{\n\t\t\tname: \"Empty map no key\",\n\t\t\tm:    map[any]any{},\n\t\t},\n\t\t{\n\t\t\tname: \"Empty map with key\",\n\t\t\tkey:  \"foo\",\n\t\t\tm:    map[any]any{},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 1 no key\",\n\t\t\tkey:  \".foob\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": 10,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 1\",\n\t\t\tkey:  \"foobar\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foobar\": 10,\n\t\t\t},\n\t\t\tval:   \"10\",\n\t\t\tfound: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Level 2\",\n\t\t\tkey:  \"foo.bar\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": 10,\n\t\t\t\t},\n\t\t\t},\n\t\t\tval:   \"10\",\n\t\t\tfound: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Level 2 invalid key\",\n\t\t\tkey:  \"foo.bar1\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": \"10\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 2 string map type\",\n\t\t\tkey:  \"foo.bar1\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[string]any{\n\t\t\t\t\t\"bar\": \"10\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 3 no entry\",\n\t\t\tkey:  \"foo.bar.t\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": \"sss\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 3\",\n\t\t\tkey:  \"foo.bar.t\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": map[any]any{\n\t\t\t\t\t\t\"t\": \"sss\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tval:   \"sss\",\n\t\t\tfound: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Level 3 invalid key\",\n\t\t\tkey:  \"foo.bar.t\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": map[any]any{\n\t\t\t\t\t\t\"t1\": 10,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 4 no entry\",\n\t\t\tkey:  \"foo.bar.t.gh\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": map[any]any{\n\t\t\t\t\t\t\"t1\": 10,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Level 4 slice entry\",\n\t\t\tkey:  \"foo.bar.t.gh\",\n\t\t\tm: map[any]any{\n\t\t\t\t\"foo\": map[any]any{\n\t\t\t\t\t\"bar\": map[string]any{\n\t\t\t\t\t\t\"t\": map[any]any{\n\t\t\t\t\t\t\t\"gh\": []int{10},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tval:   \"[10]\",\n\t\t\tfound: true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.key, func(t *testing.T) {\n\t\t\tms := NewMapSource(\"test\", test.m)\n\t\t\tm := NewMapValueSource(test.key, ms)\n\t\t\tval, b := m.Lookup()\n\t\t\tif !test.found {\n\t\t\t\tassert.False(t, b)\n\t\t\t} else {\n\t\t\t\tassert.True(t, b)\n\t\t\t\tassert.Equal(t, val, test.val)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMapValueSourceStringer(t *testing.T) {\n\tm := map[any]any{\n\t\t\"foo\": map[any]any{\n\t\t\t\"bar\": 10,\n\t\t},\n\t}\n\tmvs := NewMapValueSource(\"bar\", NewMapSource(\"test\", m))\n\n\tassert.Equal(t, `&mapValueSource{key:\"bar\", src:&mapSource{name:\"test\"}}`, mvs.GoString())\n\tassert.Equal(t, `key \"bar\" from map source \"test\"`, mvs.String())\n}\n"
  }
]