Full Code of urfave/cli for AI

main a107ee4e9d5a cached
161 files
890.6 KB
264.1k tokens
1011 symbols
1 requests
Download .txt
Showing preview only (938K chars total). Download the full file or copy to clipboard to get everything.
Repository: urfave/cli
Branch: main
Commit: a107ee4e9d5a
Files: 161
Total size: 890.6 KB

Directory structure:
gitextract_oit1zf28/

├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE/
│   │   ├── question.md
│   │   ├── v1-bug-report.md
│   │   ├── v2-bug-report.md
│   │   ├── v3-bug-report.md
│   │   └── v3-feature-request.md
│   ├── codecov.yml
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── lint.yml
│       ├── publish-docs.yml
│       └── test.yml
├── .gitignore
├── .golangci.yaml
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Makefile
├── README.md
├── args.go
├── args_test.go
├── autocomplete/
│   ├── bash_autocomplete
│   ├── fish_autocomplete
│   ├── powershell_autocomplete.ps1
│   └── zsh_autocomplete
├── category.go
├── cli.go
├── cli_test.go
├── command.go
├── command_parse.go
├── command_run.go
├── command_setup.go
├── command_stop_on_nth_arg_test.go
├── command_test.go
├── completion.go
├── completion_test.go
├── docs/
│   ├── CHANGELOG.md
│   ├── CNAME
│   ├── CONTRIBUTING.md
│   ├── RELEASING.md
│   ├── SECURITY.md
│   ├── go.mod
│   ├── go.sum
│   ├── index.md
│   ├── migrate-v1-to-v2.md
│   ├── migrate-v2-to-v3.md
│   ├── package.go
│   ├── v1/
│   │   ├── examples/
│   │   │   ├── arguments.md
│   │   │   ├── bash-completions.md
│   │   │   ├── combining-short-options.md
│   │   │   ├── exit-codes.md
│   │   │   ├── flags.md
│   │   │   ├── generated-help-text.md
│   │   │   ├── greet.md
│   │   │   ├── subcommands-categories.md
│   │   │   ├── subcommands.md
│   │   │   └── version-flag.md
│   │   ├── getting-started.md
│   │   └── migrating-to-v2.md
│   ├── v2/
│   │   ├── examples/
│   │   │   ├── arguments.md
│   │   │   ├── bash-completions.md
│   │   │   ├── combining-short-options.md
│   │   │   ├── exit-codes.md
│   │   │   ├── flags.md
│   │   │   ├── full-api-example.md
│   │   │   ├── generated-help-text.md
│   │   │   ├── greet.md
│   │   │   ├── subcommands-categories.md
│   │   │   ├── subcommands.md
│   │   │   ├── suggestions.md
│   │   │   ├── timestamp-flag.md
│   │   │   └── version-flag.md
│   │   ├── getting-started.md
│   │   ├── migrating-from-older-releases.md
│   │   └── migrating-to-v3.md
│   └── v3/
│       ├── examples/
│       │   ├── arguments/
│       │   │   ├── advanced.md
│       │   │   └── basics.md
│       │   ├── completions/
│       │   │   ├── customizations.md
│       │   │   └── shell-completions.md
│       │   ├── exit-codes.md
│       │   ├── flags/
│       │   │   ├── advanced.md
│       │   │   ├── basics.md
│       │   │   ├── short-options.md
│       │   │   └── value-sources.md
│       │   ├── full-api-example.md
│       │   ├── greet.md
│       │   ├── help/
│       │   │   ├── generated-help-text.md
│       │   │   └── suggestions.md
│       │   └── subcommands/
│       │       ├── basics.md
│       │       └── categories.md
│       ├── getting-started.md
│       ├── index.md
│       └── migrating-from-older-releases.md
├── docs.go
├── errors.go
├── errors_test.go
├── examples/
│   ├── example-cli/
│   │   └── example-cli.go
│   └── example-hello-world/
│       └── example-hello-world.go
├── examples_test.go
├── fish.go
├── fish_test.go
├── flag.go
├── flag_bool.go
├── flag_bool_with_inverse.go
├── flag_bool_with_inverse_test.go
├── flag_duration.go
├── flag_ext.go
├── flag_float.go
├── flag_float_slice.go
├── flag_float_slice_test.go
├── flag_float_test.go
├── flag_generic.go
├── flag_impl.go
├── flag_int.go
├── flag_int_slice.go
├── flag_int_slice_test.go
├── flag_int_test.go
├── flag_map_impl.go
├── flag_mutex.go
├── flag_mutex_test.go
├── flag_number_slice.go
├── flag_number_slice_test.go
├── flag_slice_base.go
├── flag_string.go
├── flag_string_map.go
├── flag_string_slice.go
├── flag_test.go
├── flag_timestamp.go
├── flag_uint.go
├── flag_uint_slice.go
├── flag_uint_slice_test.go
├── flag_uint_test.go
├── flag_validation_test.go
├── funcs.go
├── go.mod
├── go.sum
├── godoc-current.txt
├── help.go
├── help_test.go
├── helpers_test.go
├── mkdocs-requirements.txt
├── mkdocs.yml
├── scripts/
│   └── build.go
├── sort.go
├── sort_test.go
├── staticcheck.conf
├── suggestions.go
├── suggestions_test.go
├── template.go
├── testdata/
│   ├── empty.yml
│   ├── expected-doc-full.man
│   ├── expected-doc-full.md
│   ├── expected-doc-no-authors.md
│   ├── expected-doc-no-commands.md
│   ├── expected-doc-no-flags.md
│   ├── expected-doc-no-usagetext.md
│   ├── expected-fish-full.fish
│   ├── expected-tabular-markdown-custom-app-path.md
│   ├── expected-tabular-markdown-full.md
│   └── godoc-v3.x.txt
├── value_source.go
└── value_source_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
# See https://help.github.com/articles/about-codeowners/
# for more info about CODEOWNERS file

*       @urfave/cli


================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: ask a question
about: ask a question - assume stackoverflow's guidelines apply here
title: your question title goes here
labels: 'kind/question, status/triage, area/v2'
assignees: ''

---

my question is...


================================================
FILE: .github/ISSUE_TEMPLATE/v1-bug-report.md
================================================
---
name: v1 bug report
about: Create a report to help us fix v1 bugs
title: 'your bug title goes here'
labels: 'kind/bug, status/triage, area/v1'
assignees: ''

---

## My urfave/cli version is

_**( Put the version of urfave/cli that you are using here )**_

## Checklist

- [ ] Are you running the latest v1 release? The list of releases is [here](https://github.com/urfave/cli/releases).
- [ ] Did you check the manual for your release? The v1 manual is [here](https://cli.urfave.org/v1/getting-started/).
- [ ] 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.

## Dependency Management

<!--
  Delete any of the following that do not apply:
-->

- My project is using go modules.
- My project is using vendoring.
- My project is automatically downloading the latest version.
- I am unsure of what my dependency management setup is.

## Describe the bug

A clear and concise description of what the bug is.

## To reproduce

Describe the steps or code required to reproduce the behavior

## Observed behavior

What did you see happen immediately after the reproduction steps
above?

## Expected behavior

What would you have expected to happen immediately after the
reproduction steps above?

## Additional context

Add any other context about the problem here.

If the issue relates to a specific open source GitHub repo, please
link that repo here.

If you can reproduce this issue with a public CI system, please
link a failing build here.

## Want to fix this yourself?

We'd love to have more contributors on this project! If the fix for
this bug is easily explained and very small, feel free to create a
pull request for it. You'll want to base the PR off the `v1`
branch, all `v1` bug fix releases will be made from that branch.

## Run `go version` and paste its output here

```
# paste `go version` output in here
```

## Run `go env` and paste its output here

```
# paste `go env` output in here
```


================================================
FILE: .github/ISSUE_TEMPLATE/v2-bug-report.md
================================================
---
name: v2 bug report
about: Create a report to help us fix v2 bugs
title: 'your bug title goes here'
labels: 'kind/bug, area/v2, status/triage'
assignees: ''

---

## My urfave/cli version is

_**( Put the version of urfave/cli that you are using here )**_

## Checklist

- [ ] Are you running the latest v2 release? The list of releases is [here](https://github.com/urfave/cli/releases).
- [ ] Did you check the manual for your release? The v2 manual is [here](https://cli.urfave.org/v2/getting-started/)
- [ ] 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.

## Dependency Management

<!--
  Delete any of the following that do not apply:
-->

- My project is using go modules.
- My project is using vendoring.
- My project is automatically downloading the latest version.
- I am unsure of what my dependency management setup is.

## Describe the bug

A clear and concise description of what the bug is.

## To reproduce

Describe the steps or code required to reproduce the behavior

## Observed behavior

What did you see happen immediately after the reproduction steps
above?

## Expected behavior

What would you have expected to happen immediately after the
reproduction steps above?

## Additional context

Add any other context about the problem here.

If the issue relates to a specific open source GitHub repo, please
link that repo here.

If you can reproduce this issue with a public CI system, please
link a failing build here.

## Want to fix this yourself?

We'd love to have more contributors on this project! If the fix for
this bug is easily explained and very small, feel free to create a
pull request for it.

## Run `go version` and paste its output here

```
# paste `go version` output in here
```

## Run `go env` and paste its output here

```
# paste `go env` output in here
```


================================================
FILE: .github/ISSUE_TEMPLATE/v3-bug-report.md
================================================
---
name: v3 bug report
about: Create a report to help us fix v3 bugs
title: 'your bug title goes here'
labels: 'kind/bug, area/v3, status/triage'
assignees: ''

---

## My urfave/cli version is

_**( Put the version of urfave/cli that you are using here )**_

## Checklist

- [ ] Are you running the latest v3 release? The list of releases is [here](https://github.com/urfave/cli/releases).
- [ ] Did you check the manual for your release? The v3 manual is [here](https://cli.urfave.org/v3/getting-started/)
- [ ] 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.

## Dependency Management

<!--
  Delete any of the following that do not apply:
-->

- My project is using go modules.
- My project is using vendoring.
- My project is automatically downloading the latest version.
- I am unsure of what my dependency management setup is.

## Describe the bug

A clear and concise description of what the bug is.

## To reproduce

Describe the steps or code required to reproduce the behavior

## Observed behavior

What did you see happen immediately after the reproduction steps
above?

## Expected behavior

What would you have expected to happen immediately after the
reproduction steps above?

## Additional context

Add any other context about the problem here.

If the issue relates to a specific open source GitHub repo, please
link that repo here.

If you can reproduce this issue with a public CI system, please
link a failing build here.

## Want to fix this yourself?

We'd love to have more contributors on this project! If the fix for
this bug is easily explained and very small, feel free to create a
pull request for it.

## Run `go version` and paste its output here

```
# paste `go version` output in here
```

## Run `go env` and paste its output here

```
# paste `go env` output in here
```


================================================
FILE: .github/ISSUE_TEMPLATE/v3-feature-request.md
================================================
---
name: v3 feature request
about: Suggest an improvement to go into v3
title: 'your feature title goes here'
labels: 'type/feature, area/v3, status/triage'
assignees: ''

---

## Checklist

* [ ] Are you running the latest v3 release? The list of releases is [here](https://github.com/urfave/cli/releases).
* [ ] Did you check the manual for your release? The v3 manual is [here](https://github.com/urfave/cli/blob/main/docs/v3/index.md).
* [ ] 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.

## What problem does this solve?

A clear and concise description of what problem this feature would solve. For example:

- needing to type out the full flag name takes a long time, so I
  would like to suggest adding auto-complete
- I use (osx, windows, linux) and would like support for (some
  existing feature) to be extended to my platform
- the terminal output for a particular error case is confusing, and
  I think it could be improved

## Solution description

A detailed description of what you want to happen.

## Describe alternatives you've considered

A clear and concise description of any alternative solutions or
features you've considered.


================================================
FILE: .github/codecov.yml
================================================
comment: false
coverage:
  status:
    project:
      default:
        threshold: 5%
    patch:
      default:
        threshold: 5%
ignore:
  - examples
  - scripts


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: gomod
    directory: /
    schedule:
      interval: weekly
  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: weekly
  - package-ecosystem: pip
    directory: /
    schedule:
      interval: weekly
    groups:
      python-packages:
        patterns: ["*"]


================================================
FILE: .github/pull_request_template.md
================================================
<!--
  This template provides some ideas of things to include in your PR description.
  To start, try providing a short summary of your changes in the Title above.
  If a section of the PR template does not apply to this PR, then delete that section.
 -->

## What type of PR is this?

_(REQUIRED)_

<!--
  Delete any of the following that do not apply:
 -->

- bug
- cleanup
- documentation
- feature

## What this PR does / why we need it:

_(REQUIRED)_

<!--
  What goal is this change working towards?
  Provide a bullet pointed summary of how each file was changed.
  Briefly explain any decisions you made with respect to the changes.
  Include anything here that you didn't include in *Release Notes*
  above, such as changes to CI or changes to internal methods.
-->

## Which issue(s) this PR fixes:

_(REQUIRED)_

<!--
If this PR fixes one of more issues, list them here.
One line each, like so:

Fixes #123
Fixes #39
-->

## Special notes for your reviewer:

_(fill-in or delete this section)_

<!--
   Is there any particular feedback you would / wouldn't like?
   Which parts of the code should reviewers focus on?
-->

## Testing

_(fill-in or delete this section)_

<!--
  Describe how you tested this change.
-->

## Release Notes

_(REQUIRED)_
<!--
  If this PR makes user facing changes, please describe them here. This
  description will be copied into the release notes/changelog, whenever the
  next version is released. Keep this section short, and focus on high level
  changes.

  Put your text between the block. To omit notes, use NONE within the block.
-->

```release-note

```


================================================
FILE: .github/workflows/lint.yml
================================================
name: Run lints

on:
  push:
    tags:
      - v3.*
    branches:
      - main
  pull_request:
    branches:
      - main

permissions:
  contents: read

jobs:
  golangci-lint:
    runs-on: ubuntu-24.04

    steps:
      - name: Clone repository
        uses: actions/checkout@v6

      - name: Set up Go
        uses: actions/setup-go@v6
        with:
          go-version: stable

      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@v9
        with:
          version: latest


================================================
FILE: .github/workflows/publish-docs.yml
================================================
name: publish docs

on:
  push:
    branches:
      - main
    tags:
      - v3.*

permissions:
  contents: read

jobs:
  test-docs:
    name: test-docs
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v6

      - name: Set up Go
        uses: actions/setup-go@v6
        with:
          go-version: stable

      - name: Set PATH
        run: echo "${GITHUB_WORKSPACE}/.local/bin" >>"${GITHUB_PATH}"

      - run: make ensure-gfmrun

      - run: make gfmrun
        env:
          FLAGS: --walk docs/v3/

      - run: make diffcheck

  publish:
    permissions:
      contents: write
    if: startswith(github.ref, 'refs/tags/')
    name: publish
    needs: [test-docs]
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - uses: actions/setup-python@v6
        with:
          python-version: '3.13'
          cache: pip
          cache-dependency-path: mkdocs-requirements.txt

      - name: Ensure mkdocs is available
        run: make ensure-mkdocs

      - name: Set mkdocs remote
        run: make set-mkdocs-remote
        env:
          MKDOCS_REMOTE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Deploy via mkdocs
        run: make deploy-mkdocs


================================================
FILE: .github/workflows/test.yml
================================================
name: Run tests

on:
  push:
    branches:
      - main
    tags:
      - v3.*
  pull_request:
    branches:
      - main

permissions:
  contents: read

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-24.04, macos-15, windows-2025]
        go: [stable, oldstable]

    name: ${{ matrix.os }} @ Go ${{ matrix.go }}
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v6

      - name: Set up Go
        uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go }}

      - name: Set PATH
        run: echo "${GITHUB_WORKSPACE}/.local/bin" >>"${GITHUB_PATH}"

      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'
        run: make ensure-goimports

      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'
        run: make lint

      - run: make vet
      - run: make test
      - run: make check-binary-size

      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'
        run: make generate

      - run: make diffcheck

      - if: matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'
        run: make v3diff

      - if: success() && matrix.go == 'stable' && matrix.os == 'ubuntu-24.04'
        uses: codecov/codecov-action@v5
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true
          verbose: true


================================================
FILE: .gitignore
================================================
*.coverprofile
*.exe
*.orig
.*envrc
.envrc
.idea
/.local/
/site/
coverage.txt
examples/*/built-example
vendor


================================================
FILE: .golangci.yaml
================================================
version: "2"

formatters:
  enable:
    - gofumpt

linters:
  enable:
    - makezero
    - misspell
  exclusions:
    presets:
      - std-error-handling


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance, race,
religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
  advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting urfave-governance@googlegroups.com, a members-only group
that is world-postable. All complaints will be reviewed and investigated and
will result in a response that is deemed necessary and appropriate to the
circumstances. The project team is obligated to maintain confidentiality with
regard to the reporter of an incident. Further details of specific enforcement
policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023 urfave/cli maintainers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
# NOTE: this Makefile is meant to provide a simplified entry point for humans to
# run all of the critical steps to verify one's changes are harmonious in
# nature. Keeping target bodies to one line each and abstaining from make magic
# are very important so that maintainers and contributors can focus their
# attention on files that are primarily Go.

GO_RUN_BUILD := go run scripts/build.go

.PHONY: all
all: generate vet test check-binary-size gfmrun

# NOTE: this is a special catch-all rule to run any of the commands
# defined in scripts/build.go with optional arguments passed
# via GFLAGS (global flags) and FLAGS (command-specific flags), e.g.:
#
#   $ make test GFLAGS='--packages cli'
%:
	$(GO_RUN_BUILD) $(GFLAGS) $* $(FLAGS)

.PHONY: docs
docs:
	mkdocs build

.PHONY: serve-docs
serve-docs:
	mkdocs serve


================================================
FILE: README.md
================================================
# Welcome to urfave/cli

[![Go Reference][goreference_badge]][goreference_link]
[![Go Report Card][goreportcard_badge]][goreportcard_link]
[![codecov][codecov_badge]][codecov_link]
[![Tests status][test_badge]][test_link]

urfave/cli is a **declarative**, simple, fast, and fun package for building
command line tools in Go featuring:

- commands and subcommands with alias and prefix match support
- flexible and permissive help system
- dynamic shell completion for `bash`, `zsh`, `fish`, and `powershell`
- no dependencies except Go standard library
- input flags for simple types, slices of simple types, time, duration, and
  others
- compound short flag support (`-a` `-b` `-c` can be shortened to `-abc`)
- documentation generation in `man` and Markdown (supported via the
  [`urfave/cli-docs`][urfave/cli-docs] module)
- input lookup from:
  - environment variables
  - plain text files
  - structured file formats (supported via the
    [`urfave/cli-altsrc`][urfave/cli-altsrc] module)

## Documentation

See the hosted documentation website at <https://cli.urfave.org>. Contents of
this website are built from the [`./docs`](./docs) directory.

## Support

Check the [Q&A discussions]. If you don't find answer to your question, [create
a new discussion].

If you found a bug or have a feature request, [create a new issue].

Please keep in mind that this project is run by unpaid volunteers.

### License

See [`LICENSE`](./LICENSE).

[test_badge]: https://github.com/urfave/cli/actions/workflows/test.yml/badge.svg
[test_link]: https://github.com/urfave/cli/actions/workflows/test.yml
[goreference_badge]: https://pkg.go.dev/badge/github.com/urfave/cli/v3.svg
[goreference_link]: https://pkg.go.dev/github.com/urfave/cli/v3
[goreportcard_badge]: https://goreportcard.com/badge/github.com/urfave/cli/v3
[goreportcard_link]: https://goreportcard.com/report/github.com/urfave/cli/v3
[codecov_badge]: https://codecov.io/gh/urfave/cli/branch/main/graph/badge.svg?token=t9YGWLh05g
[codecov_link]: https://codecov.io/gh/urfave/cli
[Q&A discussions]: https://github.com/urfave/cli/discussions/categories/q-a
[create a new discussion]: https://github.com/urfave/cli/discussions/new?category=q-a
[urfave/cli-docs]: https://github.com/urfave/cli-docs
[urfave/cli-altsrc]: https://github.com/urfave/cli-altsrc
[create a new issue]: https://github.com/urfave/cli/issues/new/choose


================================================
FILE: args.go
================================================
package cli

import (
	"fmt"
	"time"
)

type Args interface {
	// Get returns the nth argument, or else a blank string
	Get(n int) string
	// First returns the first argument, or else a blank string
	First() string
	// Tail returns the rest of the arguments (not the first one)
	// or else an empty string slice
	Tail() []string
	// Len returns the length of the wrapped slice
	Len() int
	// Present checks if there are any arguments present
	Present() bool
	// Slice returns a copy of the internal slice
	Slice() []string
}

type stringSliceArgs struct {
	v []string
}

func (a *stringSliceArgs) Get(n int) string {
	if len(a.v) > n {
		return a.v[n]
	}
	return ""
}

func (a *stringSliceArgs) First() string {
	return a.Get(0)
}

func (a *stringSliceArgs) Tail() []string {
	if a.Len() >= 2 {
		tail := a.v[1:]
		ret := make([]string, len(tail))
		copy(ret, tail)
		return ret
	}

	return []string{}
}

func (a *stringSliceArgs) Len() int {
	return len(a.v)
}

func (a *stringSliceArgs) Present() bool {
	return a.Len() != 0
}

func (a *stringSliceArgs) Slice() []string {
	ret := make([]string, len(a.v))
	copy(ret, a.v)
	return ret
}

// Argument captures a positional argument that can
// be parsed
type Argument interface {
	// which this argument can be accessed using the given name
	HasName(string) bool

	// Parse the given args and return unparsed args and/or error
	Parse([]string) ([]string, error)

	// The usage template for this argument to use in help
	Usage() string

	// The Value of this Arg
	Get() any
}

// AnyArguments to differentiate between no arguments(nil) vs aleast one
var AnyArguments = []Argument{
	&StringArgs{
		Max: -1,
	},
}

type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {
	Name        string `json:"name"`      // the name of this argument
	Value       T      `json:"value"`     // the default value of this argument
	Destination *T     `json:"-"`         // the destination point for this argument
	UsageText   string `json:"usageText"` // the usage text to show
	Config      C      `json:"config"`    // config for this argument similar to Flag Config

	value *T
}

func (a *ArgumentBase[T, C, VC]) HasName(s string) bool {
	return s == a.Name
}

func (a *ArgumentBase[T, C, VC]) Usage() string {
	if a.UsageText != "" {
		return a.UsageText
	}

	usageFormat := "%[1]s"
	return fmt.Sprintf(usageFormat, a.Name)
}

func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
	tracef("calling arg%[1] parse with args %[2]", a.Name, s)

	var vc VC
	var t T
	value := vc.Create(a.Value, &t, a.Config)
	a.value = &t

	tracef("attempting arg%[1] parse", &a.Name)
	if len(s) > 0 {
		if err := value.Set(s[0]); err != nil {
			return s, fmt.Errorf("invalid value %q for argument %s: %v", s[0], a.Name, err)
		}
		*a.value = value.Get().(T)
		tracef("set arg%[1] one value", a.Name, *a.value)
	}

	if a.Destination != nil {
		tracef("setting destination")
		*a.Destination = *a.value
	}

	if len(s) > 0 {
		return s[1:], nil
	}
	return s, nil
}

func (a *ArgumentBase[T, C, VC]) Get() any {
	if a.value != nil {
		return *a.value
	}
	return a.Value
}

// ArgumentsBase is a base type for slice arguments
type ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct {
	Name        string `json:"name"`      // the name of this argument
	Value       T      `json:"value"`     // the default value of this argument
	Destination *[]T   `json:"-"`         // the destination point for this argument
	UsageText   string `json:"usageText"` // the usage text to show
	Min         int    `json:"minTimes"`  // the min num of occurrences of this argument
	Max         int    `json:"maxTimes"`  // the max num of occurrences of this argument, set to -1 for unlimited
	Config      C      `json:"config"`    // config for this argument similar to Flag Config

	values []T
}

func (a *ArgumentsBase[T, C, VC]) HasName(s string) bool {
	return s == a.Name
}

func (a *ArgumentsBase[T, C, VC]) Usage() string {
	if a.UsageText != "" {
		return a.UsageText
	}

	usageFormat := ""
	if a.Min == 0 {
		if a.Max == 1 {
			usageFormat = "[%[1]s]"
		} else {
			usageFormat = "[%[1]s ...]"
		}
	} else {
		usageFormat = "%[1]s [%[1]s ...]"
	}
	return fmt.Sprintf(usageFormat, a.Name)
}

func (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error) {
	tracef("calling arg%[1] parse with args %[2]", &a.Name, s)
	if a.Max == 0 {
		return s, fmt.Errorf("args %s has max 0, not parsing argument", a.Name)
	}
	if a.Max != -1 && a.Min > a.Max {
		return s, fmt.Errorf("args %s has min[%d] > max[%d], not parsing argument", a.Name, a.Min, a.Max)
	}

	count := 0
	var vc VC
	var t T
	value := vc.Create(a.Value, &t, a.Config)
	a.values = []T{}

	tracef("attempting arg%[1] parse", &a.Name)
	for _, arg := range s {
		if err := value.Set(arg); err != nil {
			return s, fmt.Errorf("invalid value %q for argument %s: %v", arg, a.Name, err)
		}
		tracef("set arg%[1] one value", &a.Name, value.Get().(T))
		a.values = append(a.values, value.Get().(T))
		count++
		if count >= a.Max && a.Max > -1 {
			break
		}
	}
	if count < a.Min {
		return s, fmt.Errorf("sufficient count of arg %s not provided, given %d expected %d", a.Name, count, a.Min)
	}

	if a.Destination != nil {
		tracef("appending destination")
		*a.Destination = a.values // append(*a.Destination, a.values...)
	}

	return s[count:], nil
}

func (a *ArgumentsBase[T, C, VC]) Get() any {
	if a.values != nil {
		return a.values
	}
	return []T{}
}

type (
	FloatArg      = ArgumentBase[float64, NoConfig, floatValue[float64]]
	Float32Arg    = ArgumentBase[float32, NoConfig, floatValue[float32]]
	Float64Arg    = ArgumentBase[float64, NoConfig, floatValue[float64]]
	IntArg        = ArgumentBase[int, IntegerConfig, intValue[int]]
	Int8Arg       = ArgumentBase[int8, IntegerConfig, intValue[int8]]
	Int16Arg      = ArgumentBase[int16, IntegerConfig, intValue[int16]]
	Int32Arg      = ArgumentBase[int32, IntegerConfig, intValue[int32]]
	Int64Arg      = ArgumentBase[int64, IntegerConfig, intValue[int64]]
	StringArg     = ArgumentBase[string, StringConfig, stringValue]
	StringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap]
	TimestampArg  = ArgumentBase[time.Time, TimestampConfig, timestampValue]
	UintArg       = ArgumentBase[uint, IntegerConfig, uintValue[uint]]
	Uint8Arg      = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]]
	Uint16Arg     = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]]
	Uint32Arg     = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]
	Uint64Arg     = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]

	FloatArgs     = ArgumentsBase[float64, NoConfig, floatValue[float64]]
	Float32Args   = ArgumentsBase[float32, NoConfig, floatValue[float32]]
	Float64Args   = ArgumentsBase[float64, NoConfig, floatValue[float64]]
	IntArgs       = ArgumentsBase[int, IntegerConfig, intValue[int]]
	Int8Args      = ArgumentsBase[int8, IntegerConfig, intValue[int8]]
	Int16Args     = ArgumentsBase[int16, IntegerConfig, intValue[int16]]
	Int32Args     = ArgumentsBase[int32, IntegerConfig, intValue[int32]]
	Int64Args     = ArgumentsBase[int64, IntegerConfig, intValue[int64]]
	StringArgs    = ArgumentsBase[string, StringConfig, stringValue]
	TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue]
	UintArgs      = ArgumentsBase[uint, IntegerConfig, uintValue[uint]]
	Uint8Args     = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]]
	Uint16Args    = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]]
	Uint32Args    = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]]
	Uint64Args    = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]]
)

func (c *Command) getArgValue(name string) any {
	tracef("command %s looking for args %s", c.Name, name)
	for _, arg := range c.Arguments {
		if arg.HasName(name) {
			tracef("command %s found args %s", c.Name, name)
			return arg.Get()
		}
	}
	tracef("command %s did not find args %s", c.Name, name)
	return nil
}

func arg[T any](name string, c *Command) T {
	val := c.getArgValue(name)
	if a, ok := val.(T); ok {
		return a
	}
	var zero T
	return zero
}

func (c *Command) StringArg(name string) string {
	return arg[string](name, c)
}

func (c *Command) StringArgs(name string) []string {
	return arg[[]string](name, c)
}

func (c *Command) FloatArg(name string) float64 {
	return arg[float64](name, c)
}

func (c *Command) FloatArgs(name string) []float64 {
	return arg[[]float64](name, c)
}

func (c *Command) Float32Arg(name string) float32 {
	return arg[float32](name, c)
}

func (c *Command) Float32Args(name string) []float32 {
	return arg[[]float32](name, c)
}

func (c *Command) Float64Arg(name string) float64 {
	return arg[float64](name, c)
}

func (c *Command) Float64Args(name string) []float64 {
	return arg[[]float64](name, c)
}

func (c *Command) IntArg(name string) int {
	return arg[int](name, c)
}

func (c *Command) IntArgs(name string) []int {
	return arg[[]int](name, c)
}

func (c *Command) Int8Arg(name string) int8 {
	return arg[int8](name, c)
}

func (c *Command) Int8Args(name string) []int8 {
	return arg[[]int8](name, c)
}

func (c *Command) Int16Arg(name string) int16 {
	return arg[int16](name, c)
}

func (c *Command) Int16Args(name string) []int16 {
	return arg[[]int16](name, c)
}

func (c *Command) Int32Arg(name string) int32 {
	return arg[int32](name, c)
}

func (c *Command) Int32Args(name string) []int32 {
	return arg[[]int32](name, c)
}

func (c *Command) Int64Arg(name string) int64 {
	return arg[int64](name, c)
}

func (c *Command) Int64Args(name string) []int64 {
	return arg[[]int64](name, c)
}

func (c *Command) UintArg(name string) uint {
	return arg[uint](name, c)
}

func (c *Command) Uint8Arg(name string) uint8 {
	return arg[uint8](name, c)
}

func (c *Command) Uint16Arg(name string) uint16 {
	return arg[uint16](name, c)
}

func (c *Command) Uint32Arg(name string) uint32 {
	return arg[uint32](name, c)
}

func (c *Command) Uint64Arg(name string) uint64 {
	return arg[uint64](name, c)
}

func (c *Command) UintArgs(name string) []uint {
	return arg[[]uint](name, c)
}

func (c *Command) Uint8Args(name string) []uint8 {
	return arg[[]uint8](name, c)
}

func (c *Command) Uint16Args(name string) []uint16 {
	return arg[[]uint16](name, c)
}

func (c *Command) Uint32Args(name string) []uint32 {
	return arg[[]uint32](name, c)
}

func (c *Command) Uint64Args(name string) []uint64 {
	return arg[[]uint64](name, c)
}

func (c *Command) TimestampArg(name string) time.Time {
	return arg[time.Time](name, c)
}

func (c *Command) TimestampArgs(name string) []time.Time {
	return arg[[]time.Time](name, c)
}


================================================
FILE: args_test.go
================================================
package cli

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

func TestArgNotSet(t *testing.T) {
	arg := &StringArg{
		Name:  "sa",
		Value: "foo",
	}

	require.Equal(t, "foo", arg.Get())
}

func TestArgsMaxNotSet(t *testing.T) {
	arg := &StringArgs{
		Name:  "sa",
		Value: "foo",
	}

	cmd := buildMinimalTestCommand()
	cmd.Arguments = []Argument{arg}

	err := cmd.Run(buildTestContext(t), []string{"foo", "bar"})
	require.ErrorContains(t, err, "args sa has max 0, not parsing argument")
}

func TestArgsMinGtMax(t *testing.T) {
	arg := &StringArgs{
		Name:  "sa",
		Value: "foo",
		Min:   2,
		Max:   1,
	}

	cmd := buildMinimalTestCommand()
	cmd.Arguments = []Argument{arg}

	err := cmd.Run(buildTestContext(t), []string{"foo", "bar"})
	require.ErrorContains(t, err, "args sa has min[2] > max[1], not parsing argument")
}

func TestArgsFloatTypes(t *testing.T) {
	cmd := buildMinimalTestCommand()
	var fval float64
	cmd.Arguments = []Argument{
		&FloatArg{
			Name:        "ia",
			Destination: &fval,
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "10"})
	r := require.New(t)
	r.NoError(err)
	r.Equal(float64(10), fval)
	r.Equal(float64(10), cmd.FloatArg("ia"))
	r.Equal(float64(10), cmd.Float64Arg("ia"))
	r.Equal(float32(0), cmd.Float32Arg("ia"))
	r.Equal(float64(0), cmd.FloatArg("iab"))
	r.Equal(int8(0), cmd.Int8Arg("ia"))
	r.Equal(int16(0), cmd.Int16Arg("ia"))
	r.Equal(int32(0), cmd.Int32Arg("ia"))
	r.Equal(int64(0), cmd.Int64Arg("ia"))
	r.Empty(cmd.StringArg("ia"))

	r.Error(cmd.Run(buildTestContext(t), []string{"foo", "a"}))
}

func TestArgsIntTypes(t *testing.T) {
	cmd := buildMinimalTestCommand()
	var ival int
	cmd.Arguments = []Argument{
		&IntArg{
			Name:        "ia",
			Destination: &ival,
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "10"})
	r := require.New(t)
	r.NoError(err)
	r.Equal(10, ival)
	r.Equal(10, cmd.IntArg("ia"))
	r.Equal(0, cmd.IntArg("iab"))
	r.Equal(int8(0), cmd.Int8Arg("ia"))
	r.Equal(int16(0), cmd.Int16Arg("ia"))
	r.Equal(int32(0), cmd.Int32Arg("ia"))
	r.Equal(int64(0), cmd.Int64Arg("ia"))
	r.Equal(float64(0), cmd.FloatArg("ia"))
	r.Empty(cmd.StringArg("ia"))

	r.Error(cmd.Run(buildTestContext(t), []string{"foo", "10.0"}))
}

func TestArgsFloatSliceTypes(t *testing.T) {
	cmd := buildMinimalTestCommand()
	var fval []float64
	cmd.Arguments = []Argument{
		&FloatArgs{
			Name:        "ia",
			Min:         1,
			Max:         -1,
			Destination: &fval,
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "10", "20", "30"})
	r := require.New(t)
	r.NoError(err)
	r.Equal([]float64{10, 20, 30}, fval)
	r.Equal([]float64{10, 20, 30}, cmd.FloatArgs("ia"))
	r.Equal([]float64{10, 20, 30}, cmd.Float64Args("ia"))
	r.Nil(cmd.Float32Args("ia"))

	r.Error(cmd.Run(buildTestContext(t), []string{"foo", "10", "a"}))
}

func TestArgsIntSliceTypes(t *testing.T) {
	cmd := buildMinimalTestCommand()
	var ival []int
	cmd.Arguments = []Argument{
		&IntArgs{
			Name:        "ia",
			Min:         1,
			Max:         -1,
			Destination: &ival,
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "10", "20", "30"})
	r := require.New(t)
	r.NoError(err)
	r.Equal([]int{10, 20, 30}, ival)
	r.Equal([]int{10, 20, 30}, cmd.IntArgs("ia"))
	r.Nil(cmd.Int8Args("ia"))
	r.Nil(cmd.Int16Args("ia"))
	r.Nil(cmd.Int32Args("ia"))
	r.Nil(cmd.Int64Args("ia"))

	r.Error(cmd.Run(buildTestContext(t), []string{"foo", "10", "20.0"}))
}

func TestArgsUintTypes(t *testing.T) {
	cmd := buildMinimalTestCommand()
	var ival uint
	cmd.Arguments = []Argument{
		&UintArg{
			Name:        "ia",
			Destination: &ival,
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "10"})
	r := require.New(t)
	r.NoError(err)
	r.Equal(uint(10), ival)
	r.Equal(uint(10), cmd.UintArg("ia"))
	r.Equal(uint(0), cmd.UintArg("iab"))
	r.Equal(uint8(0), cmd.Uint8Arg("ia"))
	r.Equal(uint16(0), cmd.Uint16Arg("ia"))
	r.Equal(uint32(0), cmd.Uint32Arg("ia"))
	r.Equal(uint64(0), cmd.Uint64Arg("ia"))

	r.Error(cmd.Run(buildTestContext(t), []string{"foo", "10.0"}))
}

func TestArgsUintSliceTypes(t *testing.T) {
	cmd := buildMinimalTestCommand()
	var ival []uint
	cmd.Arguments = []Argument{
		&UintArgs{
			Name:        "ia",
			Min:         1,
			Max:         -1,
			Destination: &ival,
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "10", "20", "30"})
	r := require.New(t)
	r.NoError(err)
	r.Equal([]uint{10, 20, 30}, ival)
	r.Equal([]uint{10, 20, 30}, cmd.UintArgs("ia"))
	r.Nil(cmd.Uint8Args("ia"))
	r.Nil(cmd.Uint16Args("ia"))
	r.Nil(cmd.Uint32Args("ia"))
	r.Nil(cmd.Uint64Args("ia"))

	r.Error(cmd.Run(buildTestContext(t), []string{"foo", "10", "20.0"}))
}

func TestArgumentsRootCommand(t *testing.T) {
	tests := []struct {
		name           string
		args           []string
		expectedIvals  []int
		expectedUivals []uint
		expectedFvals  []float64
		errStr         string
	}{
		{
			name:           "set ival",
			args:           []string{"foo", "10"},
			expectedIvals:  []int{10},
			expectedUivals: []uint{},
			expectedFvals:  []float64{},
		},
		{
			name:           "set invalid ival",
			args:           []string{"foo", "10.0"},
			expectedIvals:  []int{},
			expectedUivals: []uint{},
			expectedFvals:  []float64{},
			errStr:         "strconv.ParseInt: parsing \"10.0\": invalid syntax",
		},
		{
			name:           "set ival uival",
			args:           []string{"foo", "-10", "11"},
			expectedIvals:  []int{-10},
			expectedUivals: []uint{11},
			expectedFvals:  []float64{},
		},
		{
			name:           "set ival uival fval",
			args:           []string{"foo", "-12", "14", "10.1"},
			expectedIvals:  []int{-12},
			expectedUivals: []uint{14},
			expectedFvals:  []float64{10.1},
		},
		{
			name:           "set ival uival multu fvals",
			args:           []string{"foo", "-13", "12", "10.1", "11.09"},
			expectedIvals:  []int{-13},
			expectedUivals: []uint{12},
			expectedFvals:  []float64{10.1, 11.09},
		},
		{
			name:           "set fvals beyond max",
			args:           []string{"foo", "13", "10", "10.1", "11.09", "12.1"},
			expectedIvals:  []int{13},
			expectedUivals: []uint{10},
			expectedFvals:  []float64{10.1, 11.09},
			errStr:         "No help topic for '12.1'",
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			cmd := buildMinimalTestCommand()
			var ivals []int
			var uivals []uint
			var fvals []float64
			cmd.Arguments = []Argument{
				&IntArgs{
					Name:        "ia",
					Min:         1,
					Max:         1,
					Destination: &ivals,
				},
				&UintArgs{
					Name:        "uia",
					Min:         1,
					Max:         1,
					Destination: &uivals,
				},
				&FloatArgs{
					Name:        "fa",
					Min:         0,
					Max:         2,
					Destination: &fvals,
				},
			}

			err := cmd.Run(buildTestContext(t), test.args)

			r := require.New(t)

			if test.errStr != "" {
				r.ErrorContains(err, test.errStr)
			} else {
				r.Equal(test.expectedIvals, ivals)
			}
			r.Equal(test.expectedIvals, cmd.IntArgs("ia"))
			r.Equal(test.expectedFvals, cmd.FloatArgs("fa"))
			r.Equal(test.expectedUivals, cmd.UintArgs("uia"))
			/*if test.expectedFvals != nil {
				r.Equal(test.expectedFvals, fvals)
			}*/
		})
	}
}

func TestArgumentsInvalidType(t *testing.T) {
	cmd := buildMinimalTestCommand()
	cmd.Arguments = []Argument{
		&IntArgs{
			Name: "ia",
			Min:  1,
			Max:  1,
		},
	}
	r := require.New(t)
	r.Nil(cmd.StringArgs("ia"))
	r.Nil(cmd.FloatArgs("ia"))
	r.Nil(cmd.Int8Args("ia"))
	r.Nil(cmd.Int16Args("ia"))
	r.Nil(cmd.Int32Args("ia"))
	r.Nil(cmd.Int64Args("ia"))
	r.Equal(time.Time{}, cmd.TimestampArg("ia"))
	r.Nil(cmd.TimestampArgs("ia"))
	r.Nil(cmd.UintArgs("ia"))
	r.Nil(cmd.Uint8Args("ia"))
	r.Nil(cmd.Uint16Args("ia"))
	r.Nil(cmd.Uint32Args("ia"))
	r.Nil(cmd.Uint64Args("ia"))
}

func TestArgumentsSubcommand(t *testing.T) {
	tests := []struct {
		name          string
		args          []string
		expectedIval  int
		expectedSvals []string
		expectedTVals []time.Time
		errStr        string
	}{
		{
			name:   "insuff args",
			args:   []string{"foo", "subcmd", "2006-01-02T15:04:05Z"},
			errStr: "sufficient count of arg sa not provided, given 0 expected 1",
		},
		{
			name:          "set sval and tval",
			args:          []string{"foo", "subcmd", "2006-01-02T15:04:05Z", "fubar"},
			expectedIval:  10,
			expectedTVals: []time.Time{time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC)},
			expectedSvals: []string{"fubar"},
		},
		{
			name:          "set sval, tval and ival",
			args:          []string{"foo", "subcmd", "--foo", "100", "2006-01-02T15:04:05Z", "fubar", "some"},
			expectedIval:  100,
			expectedTVals: []time.Time{time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC)},
			expectedSvals: []string{"fubar", "some"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			cmd := buildMinimalTestCommand()
			var ival int
			var svals []string
			var tvals []time.Time
			cmd.Commands = []*Command{
				{
					Name: "subcmd",
					Flags: []Flag{
						&IntFlag{
							Name:        "foo",
							Value:       10,
							Destination: &ival,
						},
					},
					Arguments: []Argument{
						&TimestampArgs{
							Name:        "ta",
							Min:         1,
							Max:         1,
							Destination: &tvals,
							Config: TimestampConfig{
								Layouts: []string{time.RFC3339},
							},
						},
						&StringArgs{
							Name:        "sa",
							Min:         1,
							Max:         3,
							Destination: &svals,
						},
					},
				},
			}

			numUsageErrors := 0
			cmd.Commands[0].OnUsageError = func(ctx context.Context, cmd *Command, err error, isSubcommand bool) error {
				numUsageErrors++
				return err
			}

			err := cmd.Run(buildTestContext(t), test.args)

			r := require.New(t)

			if test.errStr != "" {
				r.ErrorContains(err, test.errStr)
				r.Equal(1, numUsageErrors)
			} else {
				if test.expectedSvals != nil {
					r.Equal(test.expectedSvals, svals)
					r.Equal(test.expectedSvals, cmd.Commands[0].StringArgs("sa"))
				}
				if test.expectedTVals != nil {
					r.Equal(test.expectedTVals, tvals)
					r.Equal(test.expectedTVals, cmd.Commands[0].TimestampArgs("ta"))
				}
				r.Equal(test.expectedIval, ival)
			}
		})
	}
}

func TestArgUsage(t *testing.T) {
	arg := &IntArg{
		Name: "ia",
	}
	tests := []struct {
		name     string
		usage    string
		expected string
	}{
		{
			name:     "default",
			expected: "ia",
		},
		{
			name:     "usage",
			usage:    "foo-usage",
			expected: "foo-usage",
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			arg.UsageText = test.usage
			require.Equal(t, test.expected, arg.Usage())
		})
	}
}

func TestArgsUsage(t *testing.T) {
	arg := &IntArgs{
		Name: "ia",
		Min:  0,
		Max:  1,
	}
	tests := []struct {
		name     string
		min      int
		max      int
		usage    string
		expected string
	}{
		{
			name:     "optional",
			min:      0,
			max:      1,
			expected: "[ia]",
		},
		{
			name:     "optional",
			min:      0,
			max:      1,
			usage:    "[my optional usage]",
			expected: "[my optional usage]",
		},
		{
			name:     "zero or more",
			min:      0,
			max:      2,
			expected: "[ia ...]",
		},
		{
			name:     "one",
			min:      1,
			max:      1,
			expected: "ia [ia ...]",
		},
		{
			name:     "many",
			min:      2,
			max:      1,
			expected: "ia [ia ...]",
		},
		{
			name:     "many2",
			min:      2,
			max:      0,
			expected: "ia [ia ...]",
		},
		{
			name:     "unlimited",
			min:      2,
			max:      -1,
			expected: "ia [ia ...]",
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			arg.Min, arg.Max, arg.UsageText = test.min, test.max, test.usage
			require.Equal(t, test.expected, arg.Usage())
		})
	}
}

func TestSingleOptionalArg(t *testing.T) {
	tests := []struct {
		name     string
		args     []string
		argValue string
		exp      string
	}{
		{
			name: "no args",
			args: []string{"foo"},
			exp:  "",
		},
		{
			name:     "no arg with def value",
			args:     []string{"foo"},
			argValue: "bar",
			exp:      "bar",
		},
		{
			name: "one arg",
			args: []string{"foo", "zbar"},
			exp:  "zbar",
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			cmd := buildMinimalTestCommand()
			var s1 string
			arg := &StringArg{
				Value:       test.argValue,
				Destination: &s1,
			}
			cmd.Arguments = []Argument{
				arg,
			}

			err := cmd.Run(buildTestContext(t), test.args) //
			r := require.New(t)
			r.NoError(err)
			r.Equal(test.exp, s1)
		})
	}
}

func TestUnboundedArgs(t *testing.T) {
	arg := &StringArgs{
		Min: 0,
		Max: -1,
	}
	tests := []struct {
		name      string
		args      []string
		defValues []string
		values    []string
		expected  []string
	}{
		{
			name:     "cmd accepts no args",
			args:     []string{"foo"},
			expected: []string{},
		},
		{
			name:     "cmd uses given args",
			args:     []string{"foo", "bar", "baz"},
			expected: []string{"bar", "baz"},
		},
		{
			name:     "cmd uses default values",
			args:     []string{"foo"},
			expected: []string{},
		},
		{
			name:     "given args override default values",
			args:     []string{"foo", "bar", "baz"},
			values:   []string{"zbar", "zbaz"},
			expected: []string{"bar", "baz"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			cmd := buildMinimalTestCommand()
			cmd.Arguments = []Argument{arg}
			arg.Destination = &test.values
			require.NoError(t, cmd.Run(context.Background(), test.args))
			require.Equal(t, test.expected, *arg.Destination)
		})
	}
}


================================================
FILE: autocomplete/bash_autocomplete
================================================
#!/bin/bash

# This is a shell completion script auto-generated by https://github.com/urfave/cli for bash.

# Macs have bash3 for which the bash-completion package doesn't include
# _init_completion. This is a minimal version of that function.
__%[1]s_init_completion() {
  COMPREPLY=()
  _get_comp_words_by_ref "$@" cur prev words cword
}

__%[1]s_bash_autocomplete() {
  if [[ "${COMP_WORDS[0]}" != "source" ]]; then
    local cur opts base words
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    if declare -F _init_completion >/dev/null 2>&1; then
      _init_completion -n "=:" || return
    else
      __%[1]s_init_completion -n "=:" || return
    fi
    words=("${words[@]:0:$cword}")
    if [[ "$cur" == "-"* ]]; then
      requestComp="${words[*]} ${cur} --generate-shell-completion"
    else
      requestComp="${words[*]} --generate-shell-completion"
    fi
    opts=$(eval "${requestComp}" 2>/dev/null)
    COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
    return 0
  fi
}

complete -o bashdefault -o default -o nospace -F __%[1]s_bash_autocomplete %[1]s


================================================
FILE: autocomplete/fish_autocomplete
================================================
# This is a shell completion script auto-generated by https://github.com/urfave/cli for fish.

function __%[1]_perform_completion
    # Extract all args except the last one
    set -l args (commandline -opc)
    # Extract the last arg (partial input)
    set -l lastArg (commandline -ct)
    
    set -l results ($args[1] $args[2..-1] $lastArg --generate-shell-completion 2> /dev/null)

    # Remove trailing empty lines
    for line in $results[-1..1]
        if test (string trim -- $line) = ""
            set results $results[1..-2]
        else
            break
        end
    end

    for line in $results
        if not string match -q -- "%[1]*" $line
            set -l parts (string split -m 1 ":" -- "$line")
            if test (count $parts) -eq 2
                printf "%s\t%s\n" "$parts[1]" "$parts[2]"
            else
                printf "%s\n" "$line"
            end
        end
    end
end

# Clear existing completions for %[1]
complete -c %[1] -e
# Register completion function
complete -c %[1] -f -a '(__%[1]_perform_completion)'

================================================
FILE: autocomplete/powershell_autocomplete.ps1
================================================
$fn = $($MyInvocation.MyCommand.Name)
$name = $fn -replace "(.*)\.ps1$", '$1'
Register-ArgumentCompleter -Native -CommandName $name -ScriptBlock {
     param($commandName, $wordToComplete, $cursorPosition)
     $other = "$wordToComplete --generate-shell-completion"
         Invoke-Expression $other | ForEach-Object {
            [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
         }
 }


================================================
FILE: autocomplete/zsh_autocomplete
================================================
#compdef %[1]s
compdef _%[1]s %[1]s

# This is a shell completion script auto-generated by https://github.com/urfave/cli for zsh.

_%[1]s() {
	local -a opts # Declare a local array
	local current
	current=${words[-1]} # -1 means "the last element"
	if [[ "$current" == "-"* ]]; then
		# Current word starts with a hyphen, so complete flags/options
		opts=("${(@f)$(${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}")
	else
		# Current word does not start with a hyphen, so complete subcommands
		opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-shell-completion)}")
	fi

	if [[ "${opts[1]}" != "" ]]; then
		_describe 'values' opts
	else
		_files
	fi
}

# Don't run the completion function when being source-ed or eval-ed.
# See https://github.com/urfave/cli/issues/1874 for discussion.
if [ "$funcstack[1]" = "_%[1]s" ]; then
	_%[1]s
fi


================================================
FILE: category.go
================================================
package cli

import "sort"

// CommandCategories interface allows for category manipulation
type CommandCategories interface {
	// AddCommand adds a command to a category, creating a new category if necessary.
	AddCommand(category string, command *Command)
	// Categories returns a slice of categories sorted by name
	Categories() []CommandCategory
}

type commandCategories []*commandCategory

func newCommandCategories() CommandCategories {
	ret := commandCategories([]*commandCategory{})
	return &ret
}

func (c *commandCategories) Less(i, j int) bool {
	return lexicographicLess((*c)[i].Name(), (*c)[j].Name())
}

func (c *commandCategories) Len() int {
	return len(*c)
}

func (c *commandCategories) Swap(i, j int) {
	(*c)[i], (*c)[j] = (*c)[j], (*c)[i]
}

func (c *commandCategories) AddCommand(category string, command *Command) {
	for _, commandCategory := range []*commandCategory(*c) {
		if commandCategory.name == category {
			commandCategory.commands = append(commandCategory.commands, command)
			return
		}
	}
	newVal := append(*c,
		&commandCategory{name: category, commands: []*Command{command}})
	*c = newVal
}

func (c *commandCategories) Categories() []CommandCategory {
	ret := make([]CommandCategory, len(*c))
	for i, cat := range *c {
		ret[i] = cat
	}
	return ret
}

// CommandCategory is a category containing commands.
type CommandCategory interface {
	// Name returns the category name string
	Name() string
	// VisibleCommands returns a slice of the Commands with Hidden=false
	VisibleCommands() []*Command
}

type commandCategory struct {
	name     string
	commands []*Command
}

func (c *commandCategory) Name() string {
	return c.name
}

func (c *commandCategory) VisibleCommands() []*Command {
	if c.commands == nil {
		c.commands = []*Command{}
	}

	var ret []*Command
	for _, command := range c.commands {
		if !command.Hidden {
			ret = append(ret, command)
		}
	}
	return ret
}

// FlagCategories interface allows for category manipulation
type FlagCategories interface {
	// AddFlags adds a flag to a category, creating a new category if necessary.
	AddFlag(category string, fl Flag)
	// VisibleCategories returns a slice of visible flag categories sorted by name
	VisibleCategories() []VisibleFlagCategory
}

type defaultFlagCategories struct {
	m map[string]*defaultVisibleFlagCategory
}

func newFlagCategories() FlagCategories {
	return &defaultFlagCategories{
		m: map[string]*defaultVisibleFlagCategory{},
	}
}

func newFlagCategoriesFromFlags(fs []Flag) FlagCategories {
	fc := newFlagCategories()

	var categorized bool

	for _, fl := range fs {
		if cf, ok := fl.(CategorizableFlag); ok {
			visible := false
			if vf, ok := fl.(VisibleFlag); ok {
				visible = vf.IsVisible()
			}
			if cat := cf.GetCategory(); cat != "" && visible {
				fc.AddFlag(cat, fl)
				categorized = true
			}
		}
	}

	if categorized {
		for _, fl := range fs {
			if cf, ok := fl.(CategorizableFlag); ok {
				visible := false
				if vf, ok := fl.(VisibleFlag); ok {
					visible = vf.IsVisible()
				}
				if cf.GetCategory() == "" && visible {
					fc.AddFlag("", fl)
				}
			}
		}
	}

	return fc
}

func (f *defaultFlagCategories) AddFlag(category string, fl Flag) {
	if _, ok := f.m[category]; !ok {
		f.m[category] = &defaultVisibleFlagCategory{name: category, m: map[string]Flag{}}
	}

	f.m[category].m[fl.String()] = fl
}

func (f *defaultFlagCategories) VisibleCategories() []VisibleFlagCategory {
	catNames := []string{}
	for name := range f.m {
		catNames = append(catNames, name)
	}

	sort.Strings(catNames)

	ret := make([]VisibleFlagCategory, len(catNames))
	for i, name := range catNames {
		ret[i] = f.m[name]
	}

	return ret
}

// VisibleFlagCategory is a category containing flags.
type VisibleFlagCategory interface {
	// Name returns the category name string
	Name() string
	// Flags returns a slice of VisibleFlag sorted by name
	Flags() []Flag
}

type defaultVisibleFlagCategory struct {
	name string
	m    map[string]Flag
}

func (fc *defaultVisibleFlagCategory) Name() string {
	return fc.name
}

func (fc *defaultVisibleFlagCategory) Flags() []Flag {
	vfNames := []string{}
	for flName, fl := range fc.m {
		if vf, ok := fl.(VisibleFlag); ok {
			if vf.IsVisible() {
				vfNames = append(vfNames, flName)
			}
		}
	}

	sort.Strings(vfNames)

	ret := make([]Flag, len(vfNames))
	for i, flName := range vfNames {
		ret[i] = fc.m[flName]
	}

	return ret
}


================================================
FILE: cli.go
================================================
// Package cli provides a minimal framework for creating and organizing command line
// Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows:
//
//	func main() {
//		(&cli.Command{}).Run(context.Background(), os.Args)
//	}
//
// Of course this application does not do much, so let's make this an actual application:
//
//	func main() {
//		cmd := &cli.Command{
//	  		Name: "greet",
//	  		Usage: "say a greeting",
//	  		Action: func(c *cli.Context) error {
//	  			fmt.Println("Greetings")
//	  			return nil
//	  		},
//		}
//
//		cmd.Run(context.Background(), os.Args)
//	}
package cli

import (
	"fmt"
	"os"
	"runtime"
	"strings"
)

var isTracingOn = os.Getenv("URFAVE_CLI_TRACING") == "on"

func tracef(format string, a ...any) {
	if !isTracingOn {
		return
	}

	if !strings.HasSuffix(format, "\n") {
		format = format + "\n"
	}

	pc, file, line, _ := runtime.Caller(1)
	cf := runtime.FuncForPC(pc)

	fmt.Fprintf(
		os.Stderr,
		strings.Join([]string{
			"## URFAVE CLI TRACE ",
			file,
			":",
			fmt.Sprintf("%v", line),
			" ",
			fmt.Sprintf("(%s)", cf.Name()),
			" ",
			format,
		}, ""),
		a...,
	)
}


================================================
FILE: cli_test.go
================================================
package cli

import (
	"bytes"
	"context"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func expectFileContent(t *testing.T, file, got string) {
	data, err := os.ReadFile(file)
	// Ignore windows line endings
	data = bytes.ReplaceAll(data, []byte("\r\n"), []byte("\n"))

	r := require.New(t)
	r.NoError(err)
	r.Equal(got, string(data))
}

func buildTestContext(t *testing.T) context.Context {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	t.Cleanup(cancel)

	return ctx
}

func TestTracing(t *testing.T) {
	olderr := os.Stderr
	oldtracing := isTracingOn
	defer func() {
		os.Stderr = olderr
		isTracingOn = oldtracing
	}()

	file, err := os.CreateTemp(os.TempDir(), "cli*")
	assert.NoError(t, err)
	os.Stderr = file

	// Note we cant really set the env since the isTracingOn
	// is read at module startup so any changes mid code
	// wont take effect
	isTracingOn = false
	tracef("something")

	isTracingOn = true
	tracef("foothing")

	assert.NoError(t, file.Close())

	b, err := os.ReadFile(file.Name())
	assert.NoError(t, err)

	assert.Contains(t, string(b), "foothing")
	assert.NotContains(t, string(b), "something")
}


================================================
FILE: command.go
================================================
package cli

import (
	"context"
	"fmt"
	"io"
	"slices"
	"strings"
)

const (
	// ignoreFlagPrefix is to ignore test flags when adding flags from other packages
	ignoreFlagPrefix = "test."

	commandContextKey = contextKey("cli.context")
)

type contextKey string

// Command contains everything needed to run an application that
// accepts a string slice of arguments such as os.Args. A given
// Command may contain Flags and sub-commands in Commands.
type Command struct {
	// The name of the command
	Name string `json:"name"`
	// A list of aliases for the command
	Aliases []string `json:"aliases"`
	// A short description of the usage of this command
	Usage string `json:"usage"`
	// Text to override the USAGE section of help
	UsageText string `json:"usageText"`
	// A short description of the arguments of this command
	ArgsUsage string `json:"argsUsage"`
	// Version of the command
	Version string `json:"version"`
	// Longer explanation of how the command works
	Description string `json:"description"`
	// DefaultCommand is the (optional) name of a command
	// to run if no command names are passed as CLI arguments.
	DefaultCommand string `json:"defaultCommand"`
	// The category the command is part of
	Category string `json:"category"`
	// List of child commands
	Commands []*Command `json:"commands"`
	// List of flags to parse
	Flags []Flag `json:"flags"`
	// Boolean to hide built-in help command and help flag
	HideHelp bool `json:"hideHelp"`
	// Ignored if HideHelp is true.
	HideHelpCommand bool `json:"hideHelpCommand"`
	// Boolean to hide built-in version flag and the VERSION section of help
	HideVersion bool `json:"hideVersion"`
	// Boolean to enable shell completion commands
	EnableShellCompletion bool `json:"-"`
	// Shell Completion generation command name
	ShellCompletionCommandName string `json:"-"`
	// The function to call when checking for shell command completions
	ShellComplete ShellCompleteFunc `json:"-"`
	// The function to configure a shell completion command
	ConfigureShellCompletionCommand ConfigureShellCompletionCommand `json:"-"`
	// An action to execute before any subcommands are run, but after the context is ready
	// If a non-nil error is returned, no subcommands are run
	Before BeforeFunc `json:"-"`
	// An action to execute after any subcommands are run, but after the subcommand has finished
	// It is run even if Action() panics
	After AfterFunc `json:"-"`
	// The function to call when this command is invoked
	Action ActionFunc `json:"-"`
	// Execute this function if the proper command cannot be found
	CommandNotFound CommandNotFoundFunc `json:"-"`
	// Execute this function if a usage error occurs.
	OnUsageError OnUsageErrorFunc `json:"-"`
	// Execute this function when an invalid flag is accessed from the context
	InvalidFlagAccessHandler InvalidFlagAccessFunc `json:"-"`
	// Boolean to hide this command from help or completion
	Hidden bool `json:"hidden"`
	// List of all authors who contributed (string or fmt.Stringer)
	// TODO: ~string | fmt.Stringer when interface unions are available
	Authors []any `json:"authors"`
	// Copyright of the binary if any
	Copyright string `json:"copyright"`
	// Reader reader to write input to (useful for tests)
	Reader io.Reader `json:"-"`
	// Writer writer to write output to
	Writer io.Writer `json:"-"`
	// ErrWriter writes error output
	ErrWriter io.Writer `json:"-"`
	// ExitErrHandler processes any error encountered while running a Command before it is
	// returned to the caller. If no function is provided, HandleExitCoder is used as the
	// default behavior.
	ExitErrHandler ExitErrHandlerFunc `json:"-"`
	// Other custom info
	Metadata map[string]interface{} `json:"metadata"`
	// Carries a function which returns app specific info.
	ExtraInfo func() map[string]string `json:"-"`
	// CustomRootCommandHelpTemplate the text template for app help topic.
	// cli.go uses text/template to render templates. You can
	// render custom help text by setting this variable.
	CustomRootCommandHelpTemplate string `json:"-"`
	// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is ","
	SliceFlagSeparator string `json:"sliceFlagSeparator"`
	// DisableSliceFlagSeparator is used to disable SliceFlagSeparator, the default is false
	DisableSliceFlagSeparator bool `json:"disableSliceFlagSeparator"`
	// MapFlagKeyValueSeparator is used to customize the separator for MapFlag, the default is "="
	MapFlagKeyValueSeparator string `json:"mapFlagKeyValueSeparator"`
	// Boolean to enable short-option handling so user can combine several
	// single-character bool arguments into one
	// i.e. foobar -o -v -> foobar -ov
	UseShortOptionHandling bool `json:"useShortOptionHandling"`
	// Enable suggestions for commands and flags
	Suggest bool `json:"suggest"`
	// Allows global flags set by libraries which use flag.XXXVar(...) directly
	// to be parsed through this library
	AllowExtFlags bool `json:"allowExtFlags"`
	// Treat all flags as normal arguments if true
	SkipFlagParsing bool `json:"skipFlagParsing"`
	// CustomHelpTemplate the text template for the command help topic.
	// cli.go uses text/template to render templates. You can
	// render custom help text by setting this variable.
	CustomHelpTemplate string `json:"-"`
	// Use longest prefix match for commands
	PrefixMatchCommands bool `json:"prefixMatchCommands"`
	// Custom suggest command for matching
	SuggestCommandFunc SuggestCommandFunc `json:"-"`
	// Flag exclusion group
	MutuallyExclusiveFlags []MutuallyExclusiveFlags `json:"mutuallyExclusiveFlags"`
	// Arguments to parse for this command
	Arguments []Argument `json:"arguments"`
	// Whether to read arguments from stdin
	// applicable to root command only
	ReadArgsFromStdin bool `json:"readArgsFromStdin"`
	// StopOnNthArg provides v2-like behavior for specific commands by stopping
	// flag parsing after N positional arguments are encountered. When set to N,
	// all remaining arguments after the Nth positional argument will be treated
	// as arguments, not flags.
	//
	// A value of 0 means all arguments are treated as positional (no flag parsing).
	// A nil value means normal v3 flag parsing behavior (flags can appear anywhere).
	StopOnNthArg *int `json:"stopOnNthArg"`

	// categories contains the categorized commands and is populated on app startup
	categories CommandCategories
	// flagCategories contains the categorized flags and is populated on app startup
	flagCategories FlagCategories
	// flags that have been applied in current parse
	appliedFlags []Flag
	// flags that have been set
	setFlags map[Flag]struct{}
	// The parent of this command. This value will be nil for the
	// command at the root of the graph.
	parent *Command
	// parsed args
	parsedArgs Args
	// track state of error handling
	isInError bool
	// track state of defaults
	didSetupDefaults bool
	// whether in shell completion mode
	shellCompletion bool
	// whether global help flag was added
	globaHelpFlagAdded bool
	// whether global version flag was added
	globaVersionFlagAdded bool
	// whether this is a completion command
	isCompletionCommand bool
}

// FullName returns the full name of the command.
// For commands with parents this ensures that the parent commands
// are part of the command path.
func (cmd *Command) FullName() string {
	namePath := []string{}

	if cmd.parent != nil {
		namePath = append(namePath, cmd.parent.FullName())
	}

	return strings.Join(append(namePath, cmd.Name), " ")
}

func (cmd *Command) Command(name string) *Command {
	for _, subCmd := range cmd.Commands {
		if subCmd.HasName(name) {
			return subCmd
		}
	}

	return nil
}

func (cmd *Command) checkHelp() bool {
	tracef("checking if help is wanted (cmd=%[1]q)", cmd.Name)

	return HelpFlag != nil && slices.ContainsFunc(HelpFlag.Names(), cmd.Bool)
}

func (cmd *Command) allFlags() []Flag {
	var flags []Flag
	flags = append(flags, cmd.Flags...)
	for _, grpf := range cmd.MutuallyExclusiveFlags {
		for _, f1 := range grpf.Flags {
			flags = append(flags, f1...)
		}
	}
	return flags
}

// useShortOptionHandling traverses Lineage() for *any* ancestors
// with UseShortOptionHandling
func (cmd *Command) useShortOptionHandling() bool {
	for _, pCmd := range cmd.Lineage() {
		if pCmd.UseShortOptionHandling {
			return true
		}
	}

	return false
}

func (cmd *Command) suggestFlagFromError(err error, commandName string) (string, error) {
	fl, parseErr := flagFromError(err)
	if parseErr != nil {
		return "", err
	}

	flags := cmd.Flags
	hideHelp := cmd.hideHelp()

	if commandName != "" {
		subCmd := cmd.Command(commandName)
		if subCmd == nil {
			return "", err
		}
		flags = subCmd.Flags
		hideHelp = hideHelp || subCmd.HideHelp
	}

	suggestion := SuggestFlag(flags, fl, hideHelp)
	if len(suggestion) == 0 {
		return "", err
	}

	return fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion) + "\n\n", nil
}

// Names returns the names including short names and aliases.
func (cmd *Command) Names() []string {
	return append([]string{cmd.Name}, cmd.Aliases...)
}

// HasName returns true if Command.Name matches given name
func (cmd *Command) HasName(name string) bool {
	return slices.Contains(cmd.Names(), name)
}

// VisibleCategories returns a slice of categories and commands that are
// Hidden=false
func (cmd *Command) VisibleCategories() []CommandCategory {
	ret := []CommandCategory{}
	for _, category := range cmd.categories.Categories() {
		if visible := func() CommandCategory {
			if len(category.VisibleCommands()) > 0 {
				return category
			}
			return nil
		}(); visible != nil {
			ret = append(ret, visible)
		}
	}
	return ret
}

// VisibleCommands returns a slice of the Commands with Hidden=false
func (cmd *Command) VisibleCommands() []*Command {
	var ret []*Command
	for _, command := range cmd.Commands {
		if command.Hidden || command.Name == helpName {
			continue
		}
		ret = append(ret, command)
	}
	return ret
}

// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain
func (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory {
	if cmd.flagCategories == nil {
		cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())
	}
	return cmd.flagCategories.VisibleCategories()
}

// VisibleFlags returns a slice of the Flags with Hidden=false
func (cmd *Command) VisibleFlags() []Flag {
	return visibleFlags(cmd.allFlags())
}

func (cmd *Command) appendFlag(fl Flag) {
	if !hasFlag(cmd.Flags, fl) {
		cmd.Flags = append(cmd.Flags, fl)
	}
}

// VisiblePersistentFlags returns a slice of [LocalFlag] with Persistent=true and Hidden=false.
func (cmd *Command) VisiblePersistentFlags() []Flag {
	var flags []Flag
	for _, fl := range cmd.Root().Flags {
		pfl, ok := fl.(LocalFlag)
		if !ok || pfl.IsLocal() {
			continue
		}
		flags = append(flags, fl)
	}
	return visibleFlags(flags)
}

func (cmd *Command) appendCommand(aCmd *Command) {
	if !slices.Contains(cmd.Commands, aCmd) {
		aCmd.parent = cmd
		cmd.Commands = append(cmd.Commands, aCmd)
	}
}

func (cmd *Command) handleExitCoder(ctx context.Context, err error) error {
	if cmd.parent != nil {
		return cmd.parent.handleExitCoder(ctx, err)
	}

	if cmd.ExitErrHandler != nil {
		cmd.ExitErrHandler(ctx, cmd, err)
		return err
	}

	HandleExitCoder(err)
	return err
}

func (cmd *Command) argsWithDefaultCommand(oldArgs Args) Args {
	rawArgs := append([]string{cmd.DefaultCommand}, oldArgs.Slice()...)
	newArgs := &stringSliceArgs{v: rawArgs}

	return newArgs
}

// Root returns the Command at the root of the graph
func (cmd *Command) Root() *Command {
	if cmd.parent == nil {
		return cmd
	}

	return cmd.parent.Root()
}

func (cmd *Command) set(fName string, f Flag, val string) error {
	cmd.setFlags[f] = struct{}{}
	cmd.setMultiValueParsingConfig(f)
	if err := f.Set(fName, val); err != nil {
		return fmt.Errorf("invalid value %q for flag -%s: %v", val, fName, err)
	}
	return nil
}

func (cmd *Command) lFlag(name string) Flag {
	for _, f := range cmd.allFlags() {
		if slices.Contains(f.Names(), name) {
			tracef("flag found for name %[1]q (cmd=%[2]q)", name, cmd.Name)
			return f
		}
	}
	return nil
}

func (cmd *Command) lookupFlag(name string) Flag {
	for _, pCmd := range cmd.Lineage() {
		if f := pCmd.lFlag(name); f != nil {
			return f
		}
	}

	tracef("flag NOT found for name %[1]q (cmd=%[2]q)", name, cmd.Name)
	cmd.onInvalidFlag(context.TODO(), name)
	return nil
}

// this looks up only allowed flags, i.e. local flags for current command
// or persistent flags from ancestors
func (cmd *Command) lookupAppliedFlag(name string) Flag {
	for _, f := range cmd.appliedFlags {
		if slices.Contains(f.Names(), name) {
			tracef("appliedFlag found for name %[1]q (cmd=%[2]q)", name, cmd.Name)
			return f
		}
	}

	tracef("lookupAppliedflag NOT found for name %[1]q (cmd=%[2]q)", name, cmd.Name)
	cmd.onInvalidFlag(context.TODO(), name)
	return nil
}

func (cmd *Command) checkRequiredFlag(f Flag) (bool, string) {
	if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {
		flagName := f.Names()[0]
		if !f.IsSet() {
			return false, flagName
		}
	}
	return true, ""
}

func (cmd *Command) checkAllRequiredFlags() requiredFlagsErr {
	for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {
		if err := pCmd.checkRequiredFlags(); err != nil {
			return err
		}
	}
	return nil
}

func (cmd *Command) checkRequiredFlags() requiredFlagsErr {
	tracef("checking for required flags (cmd=%[1]q)", cmd.Name)

	missingFlags := []string{}

	for _, f := range cmd.appliedFlags {
		if ok, name := cmd.checkRequiredFlag(f); !ok {
			missingFlags = append(missingFlags, name)
		}
	}

	if len(missingFlags) != 0 {
		tracef("found missing required flags %[1]q (cmd=%[2]q)", missingFlags, cmd.Name)

		return &errRequiredFlags{missingFlags: missingFlags}
	}

	tracef("all required flags set (cmd=%[1]q)", cmd.Name)

	return nil
}

func (cmd *Command) onInvalidFlag(ctx context.Context, name string) {
	for cmd != nil {
		if cmd.InvalidFlagAccessHandler != nil {
			cmd.InvalidFlagAccessHandler(ctx, cmd, name)
			break
		}
		cmd = cmd.parent
	}
}

// NumFlags returns the number of flags set
func (cmd *Command) NumFlags() int {
	tracef("numFlags numAppliedFlags %d", len(cmd.appliedFlags))
	count := 0
	for _, f := range cmd.appliedFlags {
		if f.IsSet() {
			count++
		}
	}
	return count // cmd.flagSet.NFlag()
}

func (cmd *Command) setMultiValueParsingConfig(f Flag) {
	tracef("setMultiValueParsingConfig %T, %+v", f, f)
	if cf, ok := f.(multiValueParsingConfigSetter); ok {
		cf.setMultiValueParsingConfig(multiValueParsingConfig{
			SliceFlagSeparator:        cmd.SliceFlagSeparator,
			DisableSliceFlagSeparator: cmd.DisableSliceFlagSeparator,
			MapFlagKeyValueSeparator:  cmd.MapFlagKeyValueSeparator,
		})
	}
}

// Set sets a context flag to a value.
func (cmd *Command) Set(name, value string) error {
	if f := cmd.lookupFlag(name); f != nil {
		cmd.setMultiValueParsingConfig(f)
		return f.Set(name, value)
	}

	return fmt.Errorf("no such flag -%s", name)
}

// IsSet determines if the flag was actually set
func (cmd *Command) IsSet(name string) bool {
	fl := cmd.lookupFlag(name)
	if fl == nil {
		tracef("flag with name %[1]q NOT found; assuming not set (cmd=%[2]q)", name, cmd.Name)
		return false
	}

	isSet := fl.IsSet()
	if isSet {
		tracef("flag with name %[1]q is set (cmd=%[2]q)", name, cmd.Name)
	} else {
		tracef("flag with name %[1]q is no set (cmd=%[2]q)", name, cmd.Name)
	}

	return isSet
}

// LocalFlagNames returns a slice of flag names used in this
// command.
func (cmd *Command) LocalFlagNames() []string {
	names := []string{}

	// Check the flags which have been set via env or file
	for _, f := range cmd.allFlags() {
		if f.IsSet() {
			names = append(names, f.Names()...)
		}
	}

	// Sort out the duplicates since flag could be set via multiple
	// paths
	m := map[string]struct{}{}
	uniqNames := []string{}

	for _, name := range names {
		if _, ok := m[name]; !ok {
			m[name] = struct{}{}
			uniqNames = append(uniqNames, name)
		}
	}

	return uniqNames
}

// FlagNames returns a slice of flag names used by the this command
// and all of its parent commands.
func (cmd *Command) FlagNames() []string {
	names := cmd.LocalFlagNames()

	if cmd.parent != nil {
		names = append(cmd.parent.FlagNames(), names...)
	}

	return names
}

// Lineage returns *this* command and all of its ancestor commands
// in order from child to parent
func (cmd *Command) Lineage() []*Command {
	lineage := []*Command{cmd}

	if cmd.parent != nil {
		lineage = append(lineage, cmd.parent.Lineage()...)
	}

	return lineage
}

// Count returns the num of occurrences of this flag
func (cmd *Command) Count(name string) int {
	if cf, ok := cmd.lookupFlag(name).(Countable); ok {
		return cf.Count()
	}
	return 0
}

// Value returns the value of the flag corresponding to `name`
func (cmd *Command) Value(name string) interface{} {
	if fs := cmd.lookupFlag(name); fs != nil {
		tracef("value found for name %[1]q (cmd=%[2]q)", name, cmd.Name)
		return fs.Get()
	}

	tracef("value NOT found for name %[1]q (cmd=%[2]q)", name, cmd.Name)
	return nil
}

// Args returns the command line arguments associated with the
// command.
func (cmd *Command) Args() Args {
	return cmd.parsedArgs
}

// NArg returns the number of the command line arguments.
func (cmd *Command) NArg() int {
	return cmd.Args().Len()
}

func (cmd *Command) runFlagActions(ctx context.Context) error {
	tracef("runFlagActions")
	for fl := range cmd.setFlags {
		/*tracef("checking %v:%v", fl.Names(), fl.IsSet())
		if !fl.IsSet() {
			continue
		}*/

		//if pf, ok := fl.(LocalFlag); ok && !pf.IsLocal() {
		//	continue
		//}

		if af, ok := fl.(ActionableFlag); ok {
			if err := af.RunAction(ctx, cmd); err != nil {
				return err
			}
		}
	}

	return nil
}


================================================
FILE: command_parse.go
================================================
package cli

import (
	"fmt"
	"strings"
	"unicode"
)

const (
	providedButNotDefinedErrMsg = "flag provided but not defined: -"
	argumentNotProvidedErrMsg   = "flag needs an argument: "
)

// flagFromError tries to parse a provided flag from an error message. If the
// parsing fails, it returns the input error and an empty string
func flagFromError(err error) (string, error) {
	errStr := err.Error()
	trimmed := strings.TrimPrefix(errStr, providedButNotDefinedErrMsg)
	if errStr == trimmed {
		return "", err
	}
	return trimmed, nil
}

func (cmd *Command) parseFlags(args Args) (Args, error) {
	tracef("parsing flags from arguments %[1]q (cmd=%[2]q)", args, cmd.Name)

	cmd.setFlags = map[Flag]struct{}{}
	cmd.appliedFlags = cmd.allFlags()

	tracef("walking command lineage for persistent flags (cmd=%[1]q)", cmd.Name)

	for pCmd := cmd.parent; pCmd != nil; pCmd = pCmd.parent {
		tracef(
			"checking ancestor command=%[1]q for persistent flags (cmd=%[2]q)",
			pCmd.Name, cmd.Name,
		)

		for _, fl := range pCmd.allFlags() {
			flNames := fl.Names()

			pfl, ok := fl.(LocalFlag)
			if !ok || pfl.IsLocal() {
				tracef("skipping non-persistent flag %[1]q (cmd=%[2]q)", flNames, cmd.Name)
				continue
			}

			tracef(
				"checking for applying persistent flag=%[1]q pCmd=%[2]q (cmd=%[3]q)",
				flNames, pCmd.Name, cmd.Name,
			)

			applyPersistentFlag := true

			for _, name := range flNames {
				if cmd.lFlag(name) != nil {
					applyPersistentFlag = false
					break
				}
			}

			if !applyPersistentFlag {
				tracef("not applying as persistent flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name)
				continue
			}

			tracef("applying as persistent flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name)

			tracef("appending to applied flags flag=%[1]q (cmd=%[2]q)", flNames, cmd.Name)
			cmd.appliedFlags = append(cmd.appliedFlags, fl)
		}
	}

	tracef("parsing flags iteratively tail=%[1]q (cmd=%[2]q)", args.Tail(), cmd.Name)
	defer tracef("done parsing flags (cmd=%[1]q)", cmd.Name)

	posArgs := []string{}
	for rargs := args.Slice(); len(rargs) > 0; rargs = rargs[1:] {
		tracef("rearrange:1 (cmd=%[1]q) %[2]q", cmd.Name, rargs)

		firstArg := strings.TrimSpace(rargs[0])
		if len(firstArg) == 0 {
			break
		}

		// stop parsing once we see a "--"
		if firstArg == "--" {
			posArgs = append(posArgs, rargs[1:]...)
			return &stringSliceArgs{posArgs}, nil
		}

		// Check if we've reached the Nth argument and should stop flag parsing
		if cmd.StopOnNthArg != nil && len(posArgs) == *cmd.StopOnNthArg {
			// Append current arg and all remaining args without parsing
			posArgs = append(posArgs, rargs[0:]...)
			return &stringSliceArgs{posArgs}, nil
		}

		// handle positional args
		if firstArg[0] != '-' {
			// positional argument probably
			tracef("rearrange-3 (cmd=%[1]q) check %[2]q", cmd.Name, firstArg)

			// if there is a command by that name let the command handle the
			// rest of the parsing
			if cmd.Command(firstArg) != nil {
				posArgs = append(posArgs, rargs...)
				return &stringSliceArgs{posArgs}, nil
			}

			posArgs = append(posArgs, firstArg)
			continue
		}

		numMinuses := 1
		// this is same as firstArg == "-"
		if len(firstArg) == 1 {
			posArgs = append(posArgs, firstArg)
			break
		}

		shortOptionHandling := cmd.useShortOptionHandling()

		// stop parsing -- as short flags
		if firstArg[1] == '-' {
			numMinuses++
			shortOptionHandling = false
		} else if !unicode.IsLetter(rune(firstArg[1])) {
			// this is not a flag
			tracef("parseFlags not a unicode letter. Stop parsing")
			posArgs = append(posArgs, rargs...)
			return &stringSliceArgs{posArgs}, nil
		}

		tracef("parseFlags (shortOptionHandling=%[1]q)", shortOptionHandling)

		flagName := firstArg[numMinuses:]
		flagVal := ""
		valFromEqual := false
		tracef("flagName:1 (fName=%[1]q)", flagName)
		if index := strings.Index(flagName, "="); index != -1 {
			flagVal = flagName[index+1:]
			flagName = flagName[:index]
			valFromEqual = true
		}

		tracef("flagName:2 (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal)

		f := cmd.lookupAppliedFlag(flagName)
		// found a flag matching given flagName
		if f != nil {
			tracef("Trying flag type (fName=%[1]q) (type=%[2]T)", flagName, f)
			if fb, ok := f.(boolFlag); ok && fb.IsBoolFlag() {
				if flagVal == "" {
					flagVal = "true"
				}
				tracef("parse Apply bool flag (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal)
				if err := cmd.set(flagName, f, flagVal); err != nil {
					return &stringSliceArgs{posArgs}, err
				}
				continue
			}

			tracef("processing non bool flag (fName=%[1]q)", flagName)
			// not a bool flag so need to get the next arg
			if flagVal == "" {
				if len(rargs) == 1 || valFromEqual {
					return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", argumentNotProvidedErrMsg, firstArg)
				}
				flagVal = rargs[1]
				rargs = rargs[1:]
			}

			tracef("setting non bool flag (fName=%[1]q) (fVal=%[2]q)", flagName, flagVal)
			if err := cmd.set(flagName, f, flagVal); err != nil {
				return &stringSliceArgs{posArgs}, err
			}

			continue
		}

		// no flag lookup found and short handling is disabled
		if !shortOptionHandling {
			return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName)
		}

		// try to split the flags
		for index, c := range flagName {
			tracef("processing flag (fName=%[1]q)", string(c))
			if sf := cmd.lookupFlag(string(c)); sf == nil {
				return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName)
			} else if fb, ok := sf.(boolFlag); ok && fb.IsBoolFlag() {
				fv := flagVal
				if index == (len(flagName)-1) && flagVal == "" {
					fv = "true"
				}
				if fv == "" {
					fv = "true"
				}
				if err := cmd.set(flagName, sf, fv); err != nil {
					tracef("processing flag.2 (fName=%[1]q)", string(c))
					return &stringSliceArgs{posArgs}, err
				}
			} else if index == len(flagName)-1 { // last flag can take an arg
				if flagVal == "" {
					if len(rargs) == 1 {
						return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", argumentNotProvidedErrMsg, string(c))
					}
					flagVal = rargs[1]
					rargs = rargs[1:]
				}
				tracef("parseFlags (flagName %[1]q) (flagVal %[2]q)", flagName, flagVal)
				if err := cmd.set(flagName, sf, flagVal); err != nil {
					tracef("processing flag.4 (fName=%[1]q)", string(c))
					return &stringSliceArgs{posArgs}, err
				}
			}
		}
	}

	tracef("returning-2 (cmd=%[1]q) args %[2]q", cmd.Name, posArgs)
	return &stringSliceArgs{posArgs}, nil
}


================================================
FILE: command_run.go
================================================
package cli

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"slices"
	"unicode"
)

func (cmd *Command) parseArgsFromStdin() ([]string, error) {
	type state int
	const (
		stateSearchForToken  state = -1
		stateSearchForString state = 0
	)

	st := stateSearchForToken
	linenum := 1
	token := ""
	args := []string{}

	breader := bufio.NewReader(cmd.Reader)

outer:
	for {
		ch, _, err := breader.ReadRune()
		if err == io.EOF {
			switch st {
			case stateSearchForToken:
				if token != "--" {
					args = append(args, token)
				}
			case stateSearchForString:
				// make sure string is not empty
				for _, t := range token {
					if !unicode.IsSpace(t) {
						args = append(args, token)
					}
				}
			}
			break outer
		}
		if err != nil {
			return nil, err
		}
		switch st {
		case stateSearchForToken:
			if unicode.IsSpace(ch) || ch == '"' {
				if ch == '\n' {
					linenum++
				}
				if token != "" {
					// end the processing here
					if token == "--" {
						break outer
					}
					args = append(args, token)
					token = ""
				}
				if ch == '"' {
					st = stateSearchForString
				}
				continue
			}
			token += string(ch)
		case stateSearchForString:
			if ch != '"' {
				token += string(ch)
			} else {
				if token != "" {
					args = append(args, token)
					token = ""
				}
				/*else {
					//TODO. Should we pass in empty strings ?
				}*/
				st = stateSearchForToken
			}
		}
	}

	tracef("parsed stdin args as %v (cmd=%[2]q)", args, cmd.Name)

	return args, nil
}

// Run is the entry point to the command graph. The positional
// arguments are parsed according to the Flag and Command
// definitions and the matching Action functions are run.
func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) {
	_, deferErr = cmd.run(ctx, osArgs)
	return deferErr
}

func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context, deferErr error) {
	tracef("running with arguments %[1]q (cmd=%[2]q)", osArgs, cmd.Name)
	cmd.setupDefaults(osArgs)

	// Validate StopOnNthArg
	if cmd.StopOnNthArg != nil && *cmd.StopOnNthArg < 0 {
		return ctx, fmt.Errorf("StopOnNthArg must be non-negative, got %d", *cmd.StopOnNthArg)
	}

	if v, ok := ctx.Value(commandContextKey).(*Command); ok {
		tracef("setting parent (cmd=%[1]q) command from context.Context value (cmd=%[2]q)", v.Name, cmd.Name)
		cmd.parent = v
	}

	if cmd.parent == nil {
		if cmd.ReadArgsFromStdin {
			if args, err := cmd.parseArgsFromStdin(); err != nil {
				return ctx, err
			} else {
				osArgs = append(osArgs, args...)
			}
		}
		// handle the completion flag separately from the flagset since
		// completion could be attempted after a flag, but before its value was put
		// on the command line. this causes the flagset to interpret the completion
		// flag name as the value of the flag before it which is undesirable
		// note that we can only do this because the shell autocomplete function
		// always appends the completion flag at the end of the command
		tracef("checking osArgs %v (cmd=%[2]q)", osArgs, cmd.Name)
		cmd.shellCompletion, osArgs = checkShellCompleteFlag(cmd, osArgs)

		tracef("setting cmd.shellCompletion=%[1]v from checkShellCompleteFlag (cmd=%[2]q)", cmd.shellCompletion && cmd.EnableShellCompletion, cmd.Name)
		cmd.shellCompletion = cmd.EnableShellCompletion && cmd.shellCompletion
	}

	tracef("using post-checkShellCompleteFlag arguments %[1]q (cmd=%[2]q)", osArgs, cmd.Name)

	tracef("setting self as cmd in context (cmd=%[1]q)", cmd.Name)
	ctx = context.WithValue(ctx, commandContextKey, cmd)

	if cmd.parent == nil {
		cmd.setupCommandGraph()
	}

	var rargs Args = &stringSliceArgs{v: osArgs}
	var args Args = &stringSliceArgs{rargs.Tail()}

	if cmd.isCompletionCommand || cmd.Name == helpName {
		tracef("special command detected, skipping pre-parse (cmd=%[1]q)", cmd.Name)
		cmd.parsedArgs = args
		return ctx, cmd.Action(ctx, cmd)
	}

	for _, f := range cmd.allFlags() {
		if err := f.PreParse(); err != nil {
			return ctx, err
		}
	}

	var err error

	if cmd.SkipFlagParsing {
		tracef("skipping flag parsing (cmd=%[1]q)", cmd.Name)
		cmd.parsedArgs = args
	} else {
		cmd.parsedArgs, err = cmd.parseFlags(args)
	}

	tracef("using post-parse arguments %[1]q (cmd=%[2]q)", args, cmd.Name)

	if checkCompletions(ctx, cmd) {
		return ctx, nil
	}

	if err != nil {
		tracef("setting deferErr from %[1]q (cmd=%[2]q)", err, cmd.Name)
		deferErr = err

		cmd.isInError = true
		if cmd.OnUsageError != nil {
			err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
			err = cmd.handleExitCoder(ctx, err)
			return ctx, err
		}
		fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error())
		if cmd.Suggest {
			if suggestion, err := cmd.suggestFlagFromError(err, ""); err == nil {
				fmt.Fprintf(cmd.Root().ErrWriter, "%s", suggestion)
			}
		}
		if !cmd.hideHelp() {
			if cmd.parent == nil {
				tracef("running ShowRootCommandHelp")
				if err := ShowRootCommandHelp(cmd); err != nil {
					tracef("SILENTLY IGNORING ERROR running ShowRootCommandHelp %[1]v (cmd=%[2]q)", err, cmd.Name)
				}
			} else {
				tracef("running ShowCommandHelp with %[1]q", cmd.Name)
				if err := ShowCommandHelp(ctx, cmd, cmd.Name); err != nil {
					tracef("SILENTLY IGNORING ERROR running ShowCommandHelp with %[1]q %[2]v", cmd.Name, err)
				}
			}
		}

		return ctx, err
	}

	if cmd.checkHelp() {
		return ctx, helpCommandAction(ctx, cmd)
	} else {
		tracef("no help is wanted (cmd=%[1]q)", cmd.Name)
	}

	if cmd.parent == nil && !cmd.HideVersion && checkVersion(cmd) {
		ShowVersion(cmd)
		return ctx, nil
	}

	for _, flag := range cmd.allFlags() {
		isSet := flag.IsSet()
		if err := flag.PostParse(); err != nil {
			return ctx, err
		}
		// add env set flags here
		if !isSet && flag.IsSet() {
			cmd.setFlags[flag] = struct{}{}
		}
	}

	if cmd.After != nil && !cmd.Root().shellCompletion {
		defer func() {
			if err := cmd.After(ctx, cmd); err != nil {
				err = cmd.handleExitCoder(ctx, err)

				if deferErr != nil {
					deferErr = newMultiError(deferErr, err)
				} else {
					deferErr = err
				}
			}
		}()
	}

	// Walk the parent chain to check mutually exclusive flag groups
	// defined on ancestor commands, since persistent flags are inherited.
	for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {
		for _, grp := range pCmd.MutuallyExclusiveFlags {
			if err := grp.check(cmd); err != nil {
				if cmd.OnUsageError != nil {
					err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
				} else {
					_ = ShowSubcommandHelp(cmd)
				}
				return ctx, err
			}
		}
	}

	var subCmd *Command
	if cmd.parsedArgs.Present() {
		tracef("checking positional args %[1]q (cmd=%[2]q)", cmd.parsedArgs, cmd.Name)

		name := cmd.parsedArgs.First()

		tracef("using first positional argument as sub-command name=%[1]q (cmd=%[2]q)", name, cmd.Name)

		if cmd.SuggestCommandFunc != nil && name != "--" {
			name = cmd.SuggestCommandFunc(cmd.Commands, name)
			tracef("suggested command name=%1[q] (cmd=%[2]q)", name, cmd.Name)
		}
		subCmd = cmd.Command(name)
		if subCmd == nil {
			hasDefault := cmd.DefaultCommand != ""
			isFlagName := slices.Contains(cmd.FlagNames(), name)

			if hasDefault {
				tracef("using default command=%[1]q (cmd=%[2]q)", cmd.DefaultCommand, cmd.Name)
			}

			if isFlagName || hasDefault {
				argsWithDefault := cmd.argsWithDefaultCommand(cmd.parsedArgs)
				tracef("using default command args=%[1]q (cmd=%[2]q)", argsWithDefault, cmd.Name)
				subCmd = cmd.Command(argsWithDefault.First())
				cmd.parsedArgs = argsWithDefault
			}
		}
	} else if cmd.DefaultCommand != "" {
		tracef("no positional args present; checking default command %[1]q (cmd=%[2]q)", cmd.DefaultCommand, cmd.Name)

		if dc := cmd.Command(cmd.DefaultCommand); dc != cmd {
			subCmd = dc
		}
	}

	// If a subcommand has been resolved, let it handle the remaining execution.
	if subCmd != nil {
		tracef("running sub-command %[1]q with arguments %[2]q (cmd=%[3]q)", subCmd.Name, cmd.Args(), cmd.Name)

		// It is important that we overwrite the ctx variable in the current
		// function so any defer'd functions use the new context returned
		// from the sub command.
		ctx, err = subCmd.run(ctx, cmd.Args().Slice())
		return ctx, err
	}

	// This code path is the innermost command execution. Here we actually
	// perform the command action.
	//
	// First, resolve the chain of nested commands up to the parent.
	var cmdChain []*Command
	for p := cmd; p != nil; p = p.parent {
		cmdChain = append(cmdChain, p)
	}
	slices.Reverse(cmdChain)

	// Run Before actions in order.
	for _, cmd := range cmdChain {
		if cmd.Before == nil {
			continue
		}
		if bctx, err := cmd.Before(ctx, cmd); err != nil {
			deferErr = cmd.handleExitCoder(ctx, err)
			return ctx, deferErr
		} else if bctx != nil {
			ctx = bctx
		}
	}

	// Run flag actions in order.
	// These take a context, so this has to happen after Before actions.
	for _, cmd := range cmdChain {
		tracef("running flag actions (cmd=%[1]q)", cmd.Name)
		if err := cmd.runFlagActions(ctx); err != nil {
			deferErr = cmd.handleExitCoder(ctx, err)
			return ctx, deferErr
		}
	}

	if err := cmd.checkAllRequiredFlags(); err != nil {
		cmd.isInError = true
		if cmd.OnUsageError != nil {
			err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
		} else {
			_ = ShowSubcommandHelp(cmd)
		}
		return ctx, err
	}

	// Run the command action.
	if len(cmd.Arguments) > 0 {
		rargs := cmd.Args().Slice()
		tracef("calling argparse with %[1]v", rargs)
		for _, arg := range cmd.Arguments {
			var err error
			rargs, err = arg.Parse(rargs)
			if err != nil {
				tracef("calling with %[1]v (cmd=%[2]q)", err, cmd.Name)
				if cmd.OnUsageError != nil {
					err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
				}
				err = cmd.handleExitCoder(ctx, err)
				return ctx, err
			}
		}
		cmd.parsedArgs = &stringSliceArgs{v: rargs}
	}

	if err := cmd.Action(ctx, cmd); err != nil {
		tracef("calling handleExitCoder with %[1]v (cmd=%[2]q)", err, cmd.Name)
		deferErr = cmd.handleExitCoder(ctx, err)
	}

	tracef("returning deferErr (cmd=%[1]q) %[2]q", cmd.Name, deferErr)
	return ctx, deferErr
}


================================================
FILE: command_setup.go
================================================
package cli

import (
	"flag"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

func (cmd *Command) setupDefaults(osArgs []string) {
	if cmd.didSetupDefaults {
		tracef("already did setup (cmd=%[1]q)", cmd.Name)
		return
	}

	cmd.didSetupDefaults = true

	isRoot := cmd.parent == nil
	tracef("isRoot? %[1]v (cmd=%[2]q)", isRoot, cmd.Name)

	if cmd.ShellComplete == nil {
		tracef("setting default ShellComplete (cmd=%[1]q)", cmd.Name)
		cmd.ShellComplete = DefaultCompleteWithFlags
	}

	if cmd.Name == "" && isRoot {
		name := filepath.Base(osArgs[0])
		tracef("setting cmd.Name from first arg basename (cmd=%[1]q)", name)
		cmd.Name = name
	}

	if cmd.Usage == "" && isRoot {
		tracef("setting default Usage (cmd=%[1]q)", cmd.Name)
		cmd.Usage = "A new cli application"
	}

	if cmd.Version == "" {
		tracef("setting HideVersion=true due to empty Version (cmd=%[1]q)", cmd.Name)
		cmd.HideVersion = true
	}

	if cmd.Action == nil {
		tracef("setting default Action as help command action (cmd=%[1]q)", cmd.Name)
		cmd.Action = helpCommandAction
	}

	if cmd.Reader == nil {
		tracef("setting default Reader as os.Stdin (cmd=%[1]q)", cmd.Name)
		cmd.Reader = os.Stdin
	}

	if cmd.Writer == nil {
		tracef("setting default Writer as os.Stdout (cmd=%[1]q)", cmd.Name)
		cmd.Writer = os.Stdout
	}

	if cmd.ErrWriter == nil {
		tracef("setting default ErrWriter as os.Stderr (cmd=%[1]q)", cmd.Name)
		cmd.ErrWriter = os.Stderr
	}

	if cmd.AllowExtFlags {
		tracef("visiting all flags given AllowExtFlags=true (cmd=%[1]q)", cmd.Name)
		// add global flags added by other packages
		flag.VisitAll(func(f *flag.Flag) {
			// skip test flags
			if !strings.HasPrefix(f.Name, ignoreFlagPrefix) {
				cmd.Flags = append(cmd.Flags, &extFlag{f})
			}
		})
	}

	for _, subCmd := range cmd.Commands {
		tracef("setting sub-command (cmd=%[1]q) parent as self (cmd=%[2]q)", subCmd.Name, cmd.Name)
		subCmd.parent = cmd
	}

	cmd.ensureHelp()

	if !cmd.HideVersion && isRoot {
		tracef("appending version flag (cmd=%[1]q)", cmd.Name)
		if !cmd.globaVersionFlagAdded {
			var localVersionFlag Flag
			if globalVersionFlag, ok := VersionFlag.(*BoolFlag); ok {
				flag := *globalVersionFlag
				localVersionFlag = &flag
			} else {
				localVersionFlag = VersionFlag
			}

			cmd.appendFlag(localVersionFlag)
			cmd.globaVersionFlagAdded = true
		}
	}

	if cmd.PrefixMatchCommands && cmd.SuggestCommandFunc == nil {
		tracef("setting default SuggestCommandFunc (cmd=%[1]q)", cmd.Name)
		cmd.SuggestCommandFunc = suggestCommand
	}

	if isRoot && cmd.EnableShellCompletion || cmd.ConfigureShellCompletionCommand != nil {
		completionCommand := buildCompletionCommand(cmd.Name)

		if cmd.ShellCompletionCommandName != "" {
			tracef(
				"setting completion command name (%[1]q) from "+
					"cmd.ShellCompletionCommandName (cmd=%[2]q)",
				cmd.ShellCompletionCommandName, cmd.Name,
			)
			completionCommand.Name = cmd.ShellCompletionCommandName
		}

		tracef("appending completionCommand (cmd=%[1]q)", cmd.Name)
		cmd.appendCommand(completionCommand)
		if cmd.ConfigureShellCompletionCommand != nil {
			cmd.ConfigureShellCompletionCommand(completionCommand)
		}
	}

	tracef("setting command categories (cmd=%[1]q)", cmd.Name)
	cmd.categories = newCommandCategories()

	for _, subCmd := range cmd.Commands {
		cmd.categories.AddCommand(subCmd.Category, subCmd)
	}

	tracef("sorting command categories (cmd=%[1]q)", cmd.Name)
	sort.Sort(cmd.categories.(*commandCategories))

	tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name)
	for _, grp := range cmd.MutuallyExclusiveFlags {
		grp.propagateCategory()
	}

	tracef("setting flag categories (cmd=%[1]q)", cmd.Name)
	cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())

	if cmd.Metadata == nil {
		tracef("setting default Metadata (cmd=%[1]q)", cmd.Name)
		cmd.Metadata = map[string]any{}
	}

	cmd.setFlags = map[Flag]struct{}{}
}

func (cmd *Command) setupCommandGraph() {
	tracef("setting up command graph (cmd=%[1]q)", cmd.Name)

	for _, subCmd := range cmd.Commands {
		subCmd.parent = cmd
		subCmd.setupSubcommand()
		subCmd.setupCommandGraph()
	}
}

func (cmd *Command) setupSubcommand() {
	tracef("setting up self as sub-command (cmd=%[1]q)", cmd.Name)

	cmd.ensureHelp()

	tracef("setting command categories (cmd=%[1]q)", cmd.Name)
	cmd.categories = newCommandCategories()

	for _, subCmd := range cmd.Commands {
		cmd.categories.AddCommand(subCmd.Category, subCmd)
	}

	tracef("sorting command categories (cmd=%[1]q)", cmd.Name)
	sort.Sort(cmd.categories.(*commandCategories))

	tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name)
	for _, grp := range cmd.MutuallyExclusiveFlags {
		grp.propagateCategory()
	}

	tracef("setting flag categories (cmd=%[1]q)", cmd.Name)
	cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())
}

func (cmd *Command) hideHelp() bool {
	tracef("hide help (cmd=%[1]q)", cmd.Name)
	for c := cmd; c != nil; c = c.parent {
		if c.HideHelp {
			return true
		}
	}

	return false
}

func (cmd *Command) ensureHelp() {
	tracef("ensuring help (cmd=%[1]q)", cmd.Name)

	helpCommand := buildHelpCommand(true)

	if !cmd.hideHelp() {
		if cmd.Command(helpCommand.Name) == nil {
			if !cmd.HideHelpCommand {
				tracef("appending helpCommand (cmd=%[1]q)", cmd.Name)
				cmd.appendCommand(helpCommand)
			}
		}

		if HelpFlag != nil {
			if !cmd.globaHelpFlagAdded {
				var localHelpFlag Flag
				if globalHelpFlag, ok := HelpFlag.(*BoolFlag); ok {
					flag := *globalHelpFlag
					localHelpFlag = &flag
				} else {
					localHelpFlag = HelpFlag
				}

				tracef("appending HelpFlag (cmd=%[1]q)", cmd.Name)
				cmd.appendFlag(localHelpFlag)
				cmd.globaHelpFlagAdded = true
			} else {
				tracef("HelpFlag already added, skip (cmd=%[1]q)", cmd.Name)
			}
		}
	}
}


================================================
FILE: command_stop_on_nth_arg_test.go
================================================
package cli

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCommand_StopOnNthArg(t *testing.T) {
	tests := []struct {
		name         string
		stopOnNthArg *int
		testArgs     []string
		expectedArgs []string
		expectedFlag string
		expectedBool bool
	}{
		{
			name:         "nil StopOnNthArg - normal parsing",
			stopOnNthArg: nil,
			testArgs:     []string{"cmd", "--flag", "value", "arg1", "--bool", "arg2"},
			expectedArgs: []string{"arg1", "arg2"},
			expectedFlag: "value",
			expectedBool: true,
		},
		{
			name:         "stop after 0 args - all become args",
			stopOnNthArg: intPtr(0),
			testArgs:     []string{"cmd", "--flag", "value", "arg1", "--bool", "arg2"},
			expectedArgs: []string{"--flag", "value", "arg1", "--bool", "arg2"},
			expectedFlag: "",
			expectedBool: false,
		},
		{
			name:         "stop after 1 arg",
			stopOnNthArg: intPtr(1),
			testArgs:     []string{"cmd", "--flag", "value", "arg1", "--bool", "arg2"},
			expectedArgs: []string{"arg1", "--bool", "arg2"},
			expectedFlag: "value",
			expectedBool: false,
		},
		{
			name:         "stop after 2 args",
			stopOnNthArg: intPtr(2),
			testArgs:     []string{"cmd", "--flag", "value", "arg1", "arg2", "--bool", "arg3"},
			expectedArgs: []string{"arg1", "arg2", "--bool", "arg3"},
			expectedFlag: "value",
			expectedBool: false,
		},
		{
			name:         "mixed flags and args - stop after 1",
			stopOnNthArg: intPtr(1),
			testArgs:     []string{"cmd", "--flag", "value", "--bool", "arg1", "--flag2", "value2"},
			expectedArgs: []string{"arg1", "--flag2", "value2"},
			expectedFlag: "value",
			expectedBool: true,
		},
		{
			name:         "args before flags - stop after 1",
			stopOnNthArg: intPtr(1),
			testArgs:     []string{"cmd", "arg1", "--flag", "value", "--bool"},
			expectedArgs: []string{"arg1", "--flag", "value", "--bool"},
			expectedFlag: "",
			expectedBool: false,
		},
		{
			name:         "ssh command example",
			stopOnNthArg: intPtr(1),
			testArgs:     []string{"ssh", "machine-name", "ls", "-la"},
			expectedArgs: []string{"machine-name", "ls", "-la"},
			expectedFlag: "",
			expectedBool: false,
		},
		{
			name:         "with double dash terminator",
			stopOnNthArg: intPtr(1),
			testArgs:     []string{"cmd", "--flag", "value", "--", "arg1", "--not-a-flag"},
			expectedArgs: []string{"arg1", "--not-a-flag"},
			expectedFlag: "value",
			expectedBool: false,
		},
		{
			name:         "stop after large number of args",
			stopOnNthArg: intPtr(100),
			testArgs:     []string{"cmd", "--flag", "value", "arg1", "arg2", "--bool"},
			expectedArgs: []string{"arg1", "arg2"},
			expectedFlag: "value",
			expectedBool: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var args Args
			var flagValue string
			var boolValue bool

			cmd := &Command{
				Name:         "test",
				StopOnNthArg: tt.stopOnNthArg,
				Flags: []Flag{
					&StringFlag{Name: "flag", Destination: &flagValue},
					&StringFlag{Name: "flag2"},
					&BoolFlag{Name: "bool", Destination: &boolValue},
				},
				Action: func(_ context.Context, cmd *Command) error {
					args = cmd.Args()
					return nil
				},
			}

			require.NoError(t, cmd.Run(buildTestContext(t), tt.testArgs))
			assert.Equal(t, tt.expectedArgs, args.Slice())
			assert.Equal(t, tt.expectedFlag, flagValue)
			assert.Equal(t, tt.expectedBool, boolValue)
		})
	}
}

func TestCommand_StopOnNthArg_WithSubcommands(t *testing.T) {
	tests := []struct {
		name               string
		parentStopOnNthArg *int
		subStopOnNthArg    *int
		testArgs           []string
		expectedParentArgs []string
		expectedSubArgs    []string
		expectedSubFlag    string
	}{
		{
			name:               "parent normal, subcommand stops after 0",
			parentStopOnNthArg: nil,
			subStopOnNthArg:    intPtr(0),
			testArgs:           []string{"parent", "sub", "--subflag", "value", "subarg", "--not-parsed"},
			expectedParentArgs: []string{},
			expectedSubArgs:    []string{"--subflag", "value", "subarg", "--not-parsed"},
			expectedSubFlag:    "",
		},
		{
			name:               "parent normal, subcommand stops after 1",
			parentStopOnNthArg: nil,
			subStopOnNthArg:    intPtr(1),
			testArgs:           []string{"parent", "sub", "--subflag", "value", "subarg", "--not-parsed"},
			expectedParentArgs: []string{},
			expectedSubArgs:    []string{"subarg", "--not-parsed"},
			expectedSubFlag:    "value",
		},
		{
			name:               "parent normal, subcommand stops after 2",
			parentStopOnNthArg: nil,
			subStopOnNthArg:    intPtr(2),
			testArgs:           []string{"parent", "sub", "--subflag", "value", "subarg1", "subarg2", "--not-parsed"},
			expectedParentArgs: []string{},
			expectedSubArgs:    []string{"subarg1", "subarg2", "--not-parsed"},
			expectedSubFlag:    "value",
		},
		{
			name:               "parent normal, subcommand never stops (high StopOnNthArg)",
			parentStopOnNthArg: nil,
			subStopOnNthArg:    intPtr(100),
			testArgs:           []string{"parent", "sub", "--subflag", "value1", "arg1", "arg2", "--subflag", "value2"},
			expectedParentArgs: []string{},
			expectedSubArgs:    []string{"arg1", "arg2"},
			expectedSubFlag:    "value2", // Should parse the second --subflag since we never hit the stop limit
		},
		{
			// Meaningless, but okay.
			name:               "parent stops after 1, subcommand stops after 1",
			parentStopOnNthArg: intPtr(1),
			subStopOnNthArg:    intPtr(1),
			testArgs:           []string{"parent", "sub", "--subflag", "value", "subarg", "--not-parsed"},
			expectedParentArgs: []string{},
			expectedSubArgs:    []string{"subarg", "--not-parsed"},
			expectedSubFlag:    "value",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var parentArgs, subArgs Args
			var subFlagValue string
			subCalled := false

			subCmd := &Command{
				Name:         "sub",
				StopOnNthArg: tt.subStopOnNthArg,
				Flags: []Flag{
					&StringFlag{Name: "subflag", Destination: &subFlagValue},
				},
				Action: func(_ context.Context, cmd *Command) error {
					subCalled = true
					subArgs = cmd.Args()
					return nil
				},
			}

			parentCmd := &Command{
				Name:         "parent",
				StopOnNthArg: tt.parentStopOnNthArg,
				Commands:     []*Command{subCmd},
				Flags: []Flag{
					&StringFlag{Name: "parentflag"},
				},
				Action: func(_ context.Context, cmd *Command) error {
					parentArgs = cmd.Args()
					return nil
				},
			}

			err := parentCmd.Run(buildTestContext(t), tt.testArgs)

			require.NoError(t, err)

			if tt.expectedSubArgs != nil {
				assert.True(t, subCalled, "subcommand should have been called")
				if len(tt.expectedSubArgs) > 0 {
					haveNonEmptySubArgsSlice := subArgs != nil && subArgs.Slice() != nil && len(subArgs.Slice()) > 0
					assert.True(t, haveNonEmptySubArgsSlice, "subargs.Slice is not nil")
					if haveNonEmptySubArgsSlice {
						assert.Equal(t, tt.expectedSubArgs, subArgs.Slice())
					}
				} else {
					assert.True(t, subArgs == nil || subArgs.Slice() == nil || len(subArgs.Slice()) == 0, "subargs.Slice is not nil")
				}
				assert.Equal(t, tt.expectedSubFlag, subFlagValue)
			} else {
				assert.False(t, subCalled, "subcommand should not have been called")
				assert.Equal(t, tt.expectedParentArgs, parentArgs.Slice())
			}
		})
	}
}

func TestCommand_StopOnNthArg_EdgeCases(t *testing.T) {
	t.Run("negative StopOnNthArg returns error", func(t *testing.T) {
		cmd := &Command{
			Name:         "test",
			StopOnNthArg: intPtr(-1),
			Action: func(_ context.Context, cmd *Command) error {
				return nil
			},
		}

		// Negative value should return an error
		err := cmd.Run(buildTestContext(t), []string{"cmd", "arg1"})
		require.Error(t, err)
		assert.Contains(t, err.Error(), "StopOnNthArg must be non-negative")
	})

	t.Run("zero StopOnNthArg with no args", func(t *testing.T) {
		var args Args
		var flagValue string
		cmd := &Command{
			Name:         "test",
			StopOnNthArg: intPtr(0),
			Flags: []Flag{
				&StringFlag{Name: "flag", Destination: &flagValue},
			},
			Action: func(_ context.Context, cmd *Command) error {
				args = cmd.Args()
				return nil
			},
		}

		// All flags should become args
		require.NoError(t, cmd.Run(buildTestContext(t), []string{"cmd", "--flag", "value"}))
		assert.Equal(t, []string{"--flag", "value"}, args.Slice())
		assert.Equal(t, "", flagValue)
	})

	t.Run("StopOnNthArg with only flags", func(t *testing.T) {
		var args Args
		var flagValue string
		var boolValue bool
		cmd := &Command{
			Name:         "test",
			StopOnNthArg: intPtr(1),
			Flags: []Flag{
				&StringFlag{Name: "flag", Destination: &flagValue},
				&BoolFlag{Name: "bool", Destination: &boolValue},
			},
			Action: func(_ context.Context, cmd *Command) error {
				args = cmd.Args()
				return nil
			},
		}

		// Should parse all flags since no args are encountered
		require.NoError(t, cmd.Run(buildTestContext(t), []string{"cmd", "--flag", "value", "--bool"}))
		assert.Equal(t, []string{}, args.Slice())
		assert.Equal(t, "value", flagValue)
		assert.True(t, boolValue)
	})
}

// Helper function to create int pointer
func intPtr(i int) *int {
	return &i
}


================================================
FILE: command_test.go
================================================
package cli

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/mail"
	"os"
	"sort"
	"strconv"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	lastExitCode = 0
	fakeOsExiter = func(rc int) {
		lastExitCode = rc
	}
	fakeErrWriter = &bytes.Buffer{}
)

func init() {
	OsExiter = fakeOsExiter
	ErrWriter = fakeErrWriter
}

type opCounts struct {
	Total, ShellComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
}

func buildExtendedTestCommand() *Command {
	cmd := buildMinimalTestCommand()
	cmd.Name = "greet"
	cmd.Flags = []Flag{
		&StringFlag{
			Name:      "socket",
			Aliases:   []string{"s"},
			Usage:     "some 'usage' text",
			Value:     "value",
			TakesFile: true,
		},
		&StringFlag{Name: "flag", Aliases: []string{"fl", "f"}},
		&BoolFlag{
			Name:    "another-flag",
			Aliases: []string{"b"},
			Usage:   "another usage text",
			Sources: EnvVars("EXAMPLE_VARIABLE_NAME"),
		},
		&BoolFlag{
			Name:   "hidden-flag",
			Hidden: true,
		},
	}
	cmd.Commands = []*Command{{
		Aliases: []string{"c"},
		Flags: []Flag{
			&StringFlag{
				Name:      "flag",
				Aliases:   []string{"fl", "f"},
				TakesFile: true,
			},
			&BoolFlag{
				Name:    "another-flag",
				Aliases: []string{"b"},
				Usage:   "another usage text",
			},
		},
		Name:  "config",
		Usage: "another usage test",
		Commands: []*Command{{
			Aliases: []string{"s", "ss"},
			Flags: []Flag{
				&StringFlag{Name: "sub-flag", Aliases: []string{"sub-fl", "s"}},
				&BoolFlag{
					Name:    "sub-command-flag",
					Aliases: []string{"s"},
					Usage:   "some usage text",
				},
			},
			Name:  "sub-config",
			Usage: "another usage test",
		}},
	}, {
		Aliases: []string{"i", "in"},
		Name:    "info",
		Usage:   "retrieve generic information",
	}, {
		Name: "some-command",
	}, {
		Name:   "hidden-command",
		Hidden: true,
		Flags: []Flag{
			&BoolFlag{
				Name: "completable",
			},
		},
	}, {
		Aliases: []string{"u"},
		Flags: []Flag{
			&StringFlag{
				Name:      "flag",
				Aliases:   []string{"fl", "f"},
				TakesFile: true,
			},
			&BoolFlag{
				Name:    "another-flag",
				Aliases: []string{"b"},
				Usage:   "another usage text",
			},
		},
		Name:  "usage",
		Usage: "standard usage text",
		UsageText: `
Usage for the usage text
- formatted:  Based on the specified ConfigMap and summon secrets.yml
- list:       Inspect the environment for a specific process running on a Pod
- for_effect: Compare 'namespace' environment with 'local'

` + "```" + `
func() { ... }
` + "```" + `

Should be a part of the same code block
`,
		Commands: []*Command{{
			Aliases: []string{"su"},
			Flags: []Flag{
				&BoolFlag{
					Name:    "sub-command-flag",
					Aliases: []string{"s"},
					Usage:   "some usage text",
				},
			},
			Name:      "sub-usage",
			Usage:     "standard usage text",
			UsageText: "Single line of UsageText",
		}},
	}}
	cmd.UsageText = "app [first_arg] [second_arg]"
	cmd.Description = `Description of the application.`
	cmd.Usage = "Some app"
	cmd.Authors = []any{
		"Harrison <harrison@lolwut.example.com>",
		&mail.Address{Name: "Oliver Allen", Address: "oliver@toyshop.com"},
	}

	return cmd
}

func TestCommandFlagParsing(t *testing.T) {
	cases := []struct {
		testArgs               []string
		skipFlagParsing        bool
		useShortOptionHandling bool
		expectedErr            string
	}{
		// Test normal "not ignoring flags" flow
		{testArgs: []string{"test-cmd", "-break", "blah", "blah"}, skipFlagParsing: false, useShortOptionHandling: false, expectedErr: "flag provided but not defined: -break"},
		{testArgs: []string{"test-cmd", "blah", "blah"}, skipFlagParsing: true, useShortOptionHandling: false},                                        // Test SkipFlagParsing without any args that look like flags
		{testArgs: []string{"test-cmd", "blah", "-break"}, skipFlagParsing: true, useShortOptionHandling: false},                                      // Test SkipFlagParsing with random flag arg
		{testArgs: []string{"test-cmd", "blah", "-help"}, skipFlagParsing: true, useShortOptionHandling: false},                                       // Test SkipFlagParsing with "special" help flag arg
		{testArgs: []string{"test-cmd", "blah", "-h"}, skipFlagParsing: false, useShortOptionHandling: true, expectedErr: "No help topic for 'blah'"}, // Test UseShortOptionHandling
	}

	for _, c := range cases {
		t.Run(strings.Join(c.testArgs, " "), func(t *testing.T) {
			cmd := &Command{
				Writer:          io.Discard,
				Name:            "test-cmd",
				Aliases:         []string{"tc"},
				Usage:           "this is for testing",
				Description:     "testing",
				Action:          func(context.Context, *Command) error { return nil },
				SkipFlagParsing: c.skipFlagParsing,
			}

			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
			t.Cleanup(cancel)

			r := require.New(t)

			err := cmd.Run(ctx, c.testArgs)

			if c.expectedErr != "" {
				r.EqualError(err, c.expectedErr)
			} else {
				r.NoError(err)
			}
		})
	}
}

func TestParseAndRunShortOpts(t *testing.T) {
	testCases := []struct {
		testArgs     *stringSliceArgs
		expectedErr  string
		expectedArgs Args
	}{
		{testArgs: &stringSliceArgs{v: []string{"test", "-a"}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-c", "arg1", "arg2"}}, expectedArgs: &stringSliceArgs{v: []string{"arg1", "arg2"}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-f"}}, expectedArgs: &stringSliceArgs{v: []string{}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-ac", "--fgh"}}, expectedArgs: &stringSliceArgs{v: []string{}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-af"}}, expectedArgs: &stringSliceArgs{v: []string{}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-cf"}}, expectedArgs: &stringSliceArgs{v: []string{}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-acf"}}, expectedArgs: &stringSliceArgs{v: []string{}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "--acf"}}, expectedErr: "flag provided but not defined: -acf"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-acf", "-invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "--invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-acf", "--invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-acf", "arg1", "-invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-acf", "arg1", "--invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-acfi", "not-arg", "arg1", "-invalid"}}, expectedErr: "flag provided but not defined: -invalid"},
		{testArgs: &stringSliceArgs{v: []string{"test", "-i", "ivalue"}}, expectedArgs: &stringSliceArgs{v: []string{}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-i", "ivalue", "arg1"}}, expectedArgs: &stringSliceArgs{v: []string{"arg1"}}},
		{testArgs: &stringSliceArgs{v: []string{"test", "-i"}}, expectedErr: "flag needs an argument: -i"},
	}

	for _, tc := range testCases {
		t.Run(strings.Join(tc.testArgs.v, " "), func(t *testing.T) {
			state := map[string]Args{"args": nil}

			cmd := &Command{
				Name:        "test",
				Usage:       "this is for testing",
				Description: "testing",
				Action: func(_ context.Context, cmd *Command) error {
					state["args"] = cmd.Args()
					return nil
				},
				UseShortOptionHandling: true,
				Writer:                 io.Discard,
				Flags: []Flag{
					&BoolFlag{Name: "abc", Aliases: []string{"a"}},
					&BoolFlag{Name: "cde", Aliases: []string{"c"}},
					&BoolFlag{Name: "fgh", Aliases: []string{"f"}},
					&StringFlag{Name: "ijk", Aliases: []string{"i"}},
				},
			}

			err := cmd.Run(buildTestContext(t), tc.testArgs.Slice())

			r := require.New(t)

			if tc.expectedErr == "" {
				r.NoError(err)
			} else {
				r.ErrorContains(err, tc.expectedErr)
			}

			if tc.expectedArgs == nil {
				if state["args"] != nil {
					r.Len(state["args"].Slice(), 0)
				} else {
					r.Nil(state["args"])
				}
			} else {
				r.Equal(tc.expectedArgs, state["args"])
			}
		})
	}
}

func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
	cmd := &Command{
		Name: "bar",
		Before: func(context.Context, *Command) (context.Context, error) {
			return nil, fmt.Errorf("before error")
		},
		After: func(context.Context, *Command) error {
			return fmt.Errorf("after error")
		},
		Writer: io.Discard,
	}

	err := cmd.Run(buildTestContext(t), []string{"bar"})

	require.ErrorContains(t, err, "before error")
	require.ErrorContains(t, err, "after error")
}

func TestCommand_Run_BeforeSavesMetadata(t *testing.T) {
	var receivedMsgFromAction string
	var receivedMsgFromAfter string

	cmd := &Command{
		Name: "bar",
		Before: func(ctx context.Context, cmd *Command) (context.Context, error) {
			cmd.Metadata["msg"] = "hello world"
			return nil, nil
		},
		Action: func(ctx context.Context, cmd *Command) error {
			msg, ok := cmd.Metadata["msg"]
			if !ok {
				return errors.New("msg not found")
			}
			receivedMsgFromAction = msg.(string)

			return nil
		},
		After: func(_ context.Context, cmd *Command) error {
			msg, ok := cmd.Metadata["msg"]
			if !ok {
				return errors.New("msg not found")
			}
			receivedMsgFromAfter = msg.(string)
			return nil
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"foo", "bar"}))
	require.Equal(t, "hello world", receivedMsgFromAction)
	require.Equal(t, "hello world", receivedMsgFromAfter)
}

func TestCommand_Run_BeforeReturnNewContext(t *testing.T) {
	var receivedValFromAction, receivedValFromAfter string
	type key string

	bkey := key("bkey")

	cmd := &Command{
		Name: "bar",
		Before: func(ctx context.Context, cmd *Command) (context.Context, error) {
			return context.WithValue(ctx, bkey, "bval"), nil
		},
		Action: func(ctx context.Context, cmd *Command) error {
			if val := ctx.Value(bkey); val == nil {
				return errors.New("bkey value not found")
			} else {
				receivedValFromAction = val.(string)
			}
			return nil
		},
		After: func(ctx context.Context, cmd *Command) error {
			if val := ctx.Value(bkey); val == nil {
				return errors.New("bkey value not found")
			} else {
				receivedValFromAfter = val.(string)
			}
			return nil
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"foo", "bar"}))
	require.Equal(t, "bval", receivedValFromAfter)
	require.Equal(t, "bval", receivedValFromAction)
}

type ctxKey string

// ctxCollector is a small helper to collect context values.
type ctxCollector struct {
	// keys are the keys to check the context for.
	keys []ctxKey

	// m maps from function name to context name to value.
	m map[string]map[ctxKey]string
}

func (cc *ctxCollector) collect(ctx context.Context, fnName string) {
	if cc.m == nil {
		cc.m = make(map[string]map[ctxKey]string)
	}

	if _, ok := cc.m[fnName]; !ok {
		cc.m[fnName] = make(map[ctxKey]string)
	}

	for _, k := range cc.keys {
		if val := ctx.Value(k); val != nil {
			cc.m[fnName][k] = val.(string)
		}
	}
}

func TestCommand_Run_BeforeReturnNewContextSubcommand(t *testing.T) {
	bkey := ctxKey("bkey")
	bkey2 := ctxKey("bkey2")

	cc := &ctxCollector{keys: []ctxKey{bkey, bkey2}}
	cmd := &Command{
		Name: "bar",
		Before: func(ctx context.Context, cmd *Command) (context.Context, error) {
			return context.WithValue(ctx, bkey, "bval"), nil
		},
		After: func(ctx context.Context, cmd *Command) error {
			cc.collect(ctx, "bar.After")
			return nil
		},
		Commands: []*Command{
			{
				Name: "baz",
				Before: func(ctx context.Context, cmd *Command) (context.Context, error) {
					return context.WithValue(ctx, bkey2, "bval2"), nil
				},
				Action: func(ctx context.Context, cmd *Command) error {
					cc.collect(ctx, "baz.Action")
					return nil
				},
				After: func(ctx context.Context, cmd *Command) error {
					cc.collect(ctx, "baz.After")
					return nil
				},
			},
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"bar", "baz"}))
	expected := map[string]map[ctxKey]string{
		"bar.After": {
			bkey:  "bval",
			bkey2: "bval2",
		},
		"baz.Action": {
			bkey:  "bval",
			bkey2: "bval2",
		},
		"baz.After": {
			bkey:  "bval",
			bkey2: "bval2",
		},
	}
	require.Equal(t, expected, cc.m)
}

func TestCommand_Run_FlagActionContext(t *testing.T) {
	bkey := ctxKey("bkey")
	bkey2 := ctxKey("bkey2")

	cc := &ctxCollector{keys: []ctxKey{bkey, bkey2}}
	cmd := &Command{
		Name: "bar",
		Before: func(ctx context.Context, cmd *Command) (context.Context, error) {
			return context.WithValue(ctx, bkey, "bval"), nil
		},
		Flags: []Flag{
			&StringFlag{
				Name: "foo",
				Action: func(ctx context.Context, cmd *Command, _ string) error {
					cc.collect(ctx, "bar.foo.Action")
					return nil
				},
			},
		},
		Commands: []*Command{
			{
				Name: "baz",
				Before: func(ctx context.Context, cmd *Command) (context.Context, error) {
					return context.WithValue(ctx, bkey2, "bval2"), nil
				},
				Flags: []Flag{
					&StringFlag{
						Name: "goo",
						Action: func(ctx context.Context, cmd *Command, _ string) error {
							cc.collect(ctx, "baz.goo.Action")
							return nil
						},
					},
				},
				Action: func(ctx context.Context, cmd *Command) error {
					return nil
				},
			},
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"bar", "--foo", "value", "baz", "--goo", "value"}))
	expected := map[string]map[ctxKey]string{
		"bar.foo.Action": {
			bkey:  "bval",
			bkey2: "bval2",
		},
		"baz.goo.Action": {
			bkey:  "bval",
			bkey2: "bval2",
		},
	}
	require.Equal(t, expected, cc.m)
}

func TestCommand_OnUsageError_hasCommandContext(t *testing.T) {
	cmd := &Command{
		Name: "bar",
		Flags: []Flag{
			&Int64Flag{Name: "flag"},
		},
		OnUsageError: func(_ context.Context, cmd *Command, err error, _ bool) error {
			return fmt.Errorf("intercepted in %s: %s", cmd.Name, err.Error())
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"bar", "--flag=wrong"})
	assert.ErrorContains(t, err, "intercepted in bar")
}

func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
	cmd := &Command{
		Name: "bar",
		Flags: []Flag{
			&Int64Flag{Name: "flag"},
		},
		OnUsageError: func(_ context.Context, _ *Command, err error, _ bool) error {
			assert.ErrorContains(t, err, "strconv.ParseInt: parsing \"wrong\"")
			return errors.New("intercepted: " + err.Error())
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"bar", "--flag=wrong"})
	assert.ErrorContains(t, err, "intercepted: invalid value \"wrong\" for flag -flag: strconv.ParseInt: parsing \"wrong\"")
}

func TestCommand_OnUsageError_WithSubcommand(t *testing.T) {
	cmd := &Command{
		Name: "bar",
		Commands: []*Command{
			{
				Name: "baz",
			},
		},
		Flags: []Flag{
			&Int64Flag{Name: "flag"},
		},
		OnUsageError: func(_ context.Context, _ *Command, err error, _ bool) error {
			assert.ErrorContains(t, err, "parsing \"wrong\": invalid syntax")
			return errors.New("intercepted: " + err.Error())
		},
	}

	require.ErrorContains(t, cmd.Run(buildTestContext(t), []string{"bar", "--flag=wrong"}),
		"intercepted: invalid value \"wrong\" for flag -flag: strconv.ParseInt: parsing \"wrong\": invalid syntax")
}

func TestCommand_Run_SubcommandsCanUseErrWriter(t *testing.T) {
	cmd := &Command{
		ErrWriter: io.Discard,
		Name:      "bar",
		Usage:     "this is for testing",
		Commands: []*Command{
			{
				Name:  "baz",
				Usage: "this is for testing",
				Action: func(_ context.Context, cmd *Command) error {
					require.Equal(t, io.Discard, cmd.Root().ErrWriter)

					return nil
				},
			},
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"bar", "baz"}))
}

func TestCommandSkipFlagParsing(t *testing.T) {
	cases := []struct {
		testArgs     *stringSliceArgs
		expectedArgs *stringSliceArgs
		expectedErr  error
	}{
		{testArgs: &stringSliceArgs{v: []string{"some-command", "some-arg", "--flag", "foo"}}, expectedArgs: &stringSliceArgs{v: []string{"some-arg", "--flag", "foo"}}, expectedErr: nil},
		{testArgs: &stringSliceArgs{v: []string{"some-command", "some-arg", "--flag=foo"}}, expectedArgs: &stringSliceArgs{v: []string{"some-arg", "--flag=foo"}}, expectedErr: nil},
	}

	for _, c := range cases {
		t.Run(strings.Join(c.testArgs.Slice(), " "), func(t *testing.T) {
			var args Args
			cmd := &Command{
				SkipFlagParsing: true,
				Name:            "some-command",
				Flags: []Flag{
					&StringFlag{Name: "flag"},
				},
				Action: func(_ context.Context, cmd *Command) error {
					args = cmd.Args()
					return nil
				},
				Writer: io.Discard,
			}

			err := cmd.Run(buildTestContext(t), c.testArgs.Slice())
			assert.Equal(t, c.expectedErr, err)
			assert.Equal(t, c.expectedArgs, args)
		})
	}
}

func TestCommand_Run_CustomShellCompleteAcceptsMalformedFlags(t *testing.T) {
	cases := []struct {
		testArgs    *stringSliceArgs
		expectedOut string
	}{
		{testArgs: &stringSliceArgs{v: []string{"--undefined"}}, expectedOut: "found 0 args"},
		{testArgs: &stringSliceArgs{v: []string{"--number"}}, expectedOut: "found 0 args"},
		{testArgs: &stringSliceArgs{v: []string{"--number", "forty-two"}}, expectedOut: "found 0 args"},
		{testArgs: &stringSliceArgs{v: []string{"--number", "42"}}, expectedOut: "found 0 args"},
		{testArgs: &stringSliceArgs{v: []string{"--number", "42", "newArg"}}, expectedOut: "found 1 args"},
	}

	for _, c := range cases {
		t.Run(strings.Join(c.testArgs.Slice(), " "), func(t *testing.T) {
			out := &bytes.Buffer{}
			cmd := &Command{
				Writer:                out,
				EnableShellCompletion: true,
				Name:                  "bar",
				Usage:                 "this is for testing",
				Flags: []Flag{
					&Int64Flag{
						Name:  "number",
						Usage: "A number to parse",
					},
				},
				ShellComplete: func(_ context.Context, cmd *Command) {
					fmt.Fprintf(cmd.Root().Writer, "found %[1]d args", cmd.NArg())
				},
			}

			osArgs := &stringSliceArgs{v: []string{"bar"}}
			osArgs.v = append(osArgs.v, c.testArgs.Slice()...)
			osArgs.v = append(osArgs.v, completionFlag)

			r := require.New(t)

			r.NoError(cmd.Run(buildTestContext(t), osArgs.Slice()))
			r.Equal(c.expectedOut, out.String())
		})
	}
}

func TestCommand_CanAddVFlagOnSubCommands(t *testing.T) {
	cmd := &Command{
		Version: "some version",
		Writer:  io.Discard,
		Name:    "foo",
		Usage:   "this is for testing",
		Commands: []*Command{
			{
				Name: "bar",
				Flags: []Flag{
					&BoolFlag{Name: "v"},
				},
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "bar"})
	assert.NoError(t, err)
}

func TestCommand_VisibleSubcCommands(t *testing.T) {
	subc1 := &Command{
		Name:  "subc1",
		Usage: "subc1 command1",
	}
	subc3 := &Command{
		Name:  "subc3",
		Usage: "subc3 command2",
	}
	cmd := &Command{
		Name:  "bar",
		Usage: "this is for testing",
		Commands: []*Command{
			subc1,
			{
				Name:   "subc2",
				Usage:  "subc2 command2",
				Hidden: true,
			},
			subc3,
		},
	}

	assert.Equal(t, cmd.VisibleCommands(), []*Command{subc1, subc3})
}

func TestCommand_VisibleFlagCategories(t *testing.T) {
	cmd := &Command{
		Name:  "bar",
		Usage: "this is for testing",
		Flags: []Flag{
			&StringFlag{
				Name: "strd", // no category set
			},
			&StringFlag{
				Name:   "strd1", // no category set and also hidden
				Hidden: true,
			},
			&Int64Flag{
				Name:     "intd",
				Aliases:  []string{"altd1", "altd2"},
				Category: "cat1",
			},
			&StringFlag{
				Name:     "sfd",
				Category: "cat2", // category set and hidden
				Hidden:   true,
			},
		},
		MutuallyExclusiveFlags: []MutuallyExclusiveFlags{{
			Category: "cat2",
			Flags: [][]Flag{
				{
					&StringFlag{
						Name: "mutex",
					},
				},
			},
		}},
	}

	cmd.MutuallyExclusiveFlags[0].propagateCategory()

	vfc := cmd.VisibleFlagCategories()
	require.Len(t, vfc, 3)

	assert.Equal(t, vfc[0].Name(), "", "expected category name to be empty")
	assert.Equal(t, vfc[0].Flags()[0].Names(), []string{"strd"})

	assert.Equal(t, vfc[1].Name(), "cat1", "expected category name cat1")
	require.Len(t, vfc[1].Flags(), 1, "expected flag category to have one flag")
	assert.Equal(t, vfc[1].Flags()[0].Names(), []string{"intd", "altd1", "altd2"})

	assert.Equal(t, vfc[2].Name(), "cat2", "expected category name cat2")
	require.Len(t, vfc[2].Flags(), 1, "expected flag category to have one flag")
	assert.Equal(t, vfc[2].Flags()[0].Names(), []string{"mutex"})
}

func TestCommand_RunSubcommandWithDefault(t *testing.T) {
	cmd := &Command{
		Version:        "some version",
		Name:           "app",
		DefaultCommand: "foo",
		Commands: []*Command{
			{
				Name: "foo",
				Action: func(context.Context, *Command) error {
					return errors.New("should not run this subcommand")
				},
			},
			{
				Name:     "bar",
				Usage:    "this is for testing",
				Commands: []*Command{{}}, // some subcommand
				Action: func(context.Context, *Command) error {
					return nil
				},
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"app", "bar"})
	assert.NoError(t, err)

	err = cmd.Run(buildTestContext(t), []string{"app"})
	assert.EqualError(t, err, "should not run this subcommand")
}

func TestCommand_Run(t *testing.T) {
	s := ""

	cmd := &Command{
		Action: func(_ context.Context, cmd *Command) error {
			s = s + cmd.Args().First()
			return nil
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"command", "foo"})
	assert.NoError(t, err)
	err = cmd.Run(buildTestContext(t), []string{"command", "bar"})
	assert.NoError(t, err)
	assert.Equal(t, s, "foobar")
}

var commandTests = []struct {
	name     string
	expected bool
}{
	{"foobar", true},
	{"batbaz", true},
	{"b", true},
	{"f", true},
	{"bat", false},
	{"nothing", false},
}

func TestCommand_Command(t *testing.T) {
	cmd := &Command{
		Commands: []*Command{
			{Name: "foobar", Aliases: []string{"f"}},
			{Name: "batbaz", Aliases: []string{"b"}},
		},
	}

	for _, test := range commandTests {
		if test.expected {
			assert.NotEmpty(t, cmd.Command(test.name))
		} else {
			assert.Empty(t, cmd.Command(test.name))
		}
	}
}

var defaultCommandTests = []struct {
	cmdName        string
	defaultCmd     string
	args           []string
	errNotExpected bool
}{
	{"foobar", "foobar", nil, true},
	{"batbaz", "foobar", nil, true},
	{"b", "", nil, true},
	{"f", "", nil, true},
	{"", "foobar", nil, true},
	{"", "", nil, true},
	{" ", "", nil, true},
	{"bat", "batbaz", nil, true},
	{"nothing", "batbaz", nil, true},
	{"nothing", "", nil, false},
	{"foobar", "foobar", []string{"xy", "zdf"}, true},
	{"", "foobar", []string{"xy", "zdf"}, true},
}

func TestCommand_RunDefaultCommand(t *testing.T) {
	for _, test := range defaultCommandTests {
		testTitle := fmt.Sprintf("command=%[1]s-default=%[2]s-args=%[3]v", test.cmdName, test.defaultCmd, test.args)
		t.Run(testTitle, func(t *testing.T) {
			fooCount := 0
			var fooArgs Args
			barCount := 0
			cmd := &Command{
				DefaultCommand: test.defaultCmd,
				Commands: []*Command{
					{
						Name:    "foobar",
						Aliases: []string{"f"},
						Action: func(ctx context.Context, c *Command) error {
							fooCount++
							fooArgs = c.Args()
							return nil
						},
					},
					{
						Name:    "batbaz",
						Aliases: []string{"b"},
						Action: func(ctx context.Context, c *Command) error {
							barCount++
							return nil
						},
					},
				},
			}

			runArgs := []string{"c"}
			if test.cmdName != "" {
				runArgs = append(runArgs, test.cmdName)
			}
			if test.args != nil {
				runArgs = append(runArgs, test.args...)
			}
			err := cmd.Run(buildTestContext(t), runArgs)
			if test.errNotExpected {
				assert.NoError(t, err)
				if fooCount == 0 && barCount == 0 && test.defaultCmd != "" {
					t.Errorf("expected one of the commands to run")
				}
				if fooCount > 0 {
					expectedArgs := &stringSliceArgs{v: []string{}}
					if len(test.args) > 0 && (test.args[0] == "foobar" || test.args[0] == "f") {
						expectedArgs = &stringSliceArgs{v: test.args[1:]}
					} else if test.args != nil {
						expectedArgs = &stringSliceArgs{v: test.args}
					}
					assert.Equal(t, expectedArgs, fooArgs)
				}
			} else {
				if fooCount > 0 || barCount > 0 {
					t.Errorf("expected no commands to run")
				}
				assert.Error(t, err)
			}
		})
	}
}

var defaultCommandSubCommandTests = []struct {
	cmdName        string
	subCmd         string
	defaultCmd     string
	errNotExpected bool
}{
	{"foobar", "", "foobar", true},
	{"foobar", "carly", "foobar", true},
	{"batbaz", "", "foobar", true},
	{"b", "", "", true},
	{"f", "", "", true},
	{"", "", "foobar", true},
	{"", "", "", true},
	{"", "jimbob", "foobar", true},
	{"", "j", "foobar", true},
	{"", "carly", "foobar", true},
	{"", "jimmers", "foobar", false},
	{"", "jimmers", "", false},
	{" ", "jimmers", "foobar", true},
	{"", "", "", true},
	{" ", "", "", true},
	{" ", "j", "", true},
	{"bat", "", "batbaz", false},
	{"nothing", "", "batbaz", false},
	{"nothing", "", "", false},
	{"nothing", "j", "batbaz", false},
	{"nothing", "carly", "", false},
}

func TestCommand_RunDefaultCommandWithSubCommand(t *testing.T) {
	for _, test := range defaultCommandSubCommandTests {
		testTitle := fmt.Sprintf("command=%[1]s-subcmd=%[2]s-default=%[3]s", test.cmdName, test.subCmd, test.defaultCmd)
		t.Run(testTitle, func(t *testing.T) {
			cmd := &Command{
				DefaultCommand: test.defaultCmd,
				Commands: []*Command{
					{
						Name:    "foobar",
						Aliases: []string{"f"},
						Commands: []*Command{
							{Name: "jimbob", Aliases: []string{"j"}},
							{Name: "carly"},
						},
					},
					{Name: "batbaz", Aliases: []string{"b"}},
				},
			}

			runArgs := []string{"c"}
			if test.cmdName != "" {
				runArgs = append(runArgs, test.cmdName)
			}
			if test.subCmd != "" {
				runArgs = append(runArgs, test.subCmd)
			}
			err := cmd.Run(buildTestContext(t), runArgs)
			if test.errNotExpected {
				assert.NoError(t, err)
			} else {
				assert.Error(t, err)
			}
		})
	}
}

var defaultCommandFlagTests = []struct {
	cmdName        string
	flag           string
	defaultCmd     string
	errNotExpected bool
}{
	{"foobar", "", "foobar", true},
	{"foobar", "-c derp", "foobar", true},
	{"batbaz", "", "foobar", true},
	{"b", "", "", true},
	{"f", "", "", true},
	{"", "", "foobar", true},
	{"", "", "", true},
	{"", "-j", "foobar", true},
	{"", "-j", "foobar", true},
	{"", "-c derp", "foobar", true},
	{"", "--carly=derp", "foobar", true},
	{"", "-j", "foobar", true},
	{"", "-j", "", true},
	{" ", "-j", "foobar", true},
	{"", "", "", true},
	{" ", "", "", true},
	{" ", "-j", "", true},
	{"bat", "", "batbaz", false},
	{"nothing", "", "batbaz", false},
	{"nothing", "", "", false},
	{"nothing", "--jimbob", "batbaz", false},
	{"nothing", "--carly", "", false},
}

func TestCommand_RunDefaultCommandWithFlags(t *testing.T) {
	for _, test := range defaultCommandFlagTests {
		testTitle := fmt.Sprintf("command=%[1]s-flag=%[2]s-default=%[3]s", test.cmdName, test.flag, test.defaultCmd)
		t.Run(testTitle, func(t *testing.T) {
			cmd := &Command{
				DefaultCommand: test.defaultCmd,
				Flags: []Flag{
					&StringFlag{
						Name:     "carly",
						Aliases:  []string{"c"},
						Required: false,
					},
					&BoolFlag{
						Name:     "jimbob",
						Aliases:  []string{"j"},
						Required: false,
						Value:    true,
					},
				},
				Commands: []*Command{
					{
						Name:    "foobar",
						Aliases: []string{"f"},
					},
					{Name: "batbaz", Aliases: []string{"b"}},
				},
			}

			appArgs := []string{"c"}

			if test.flag != "" {
				flags := strings.Split(test.flag, " ")
				if len(flags) > 1 {
					appArgs = append(appArgs, flags...)
				}

				flags = strings.Split(test.flag, "=")
				if len(flags) > 1 {
					appArgs = append(appArgs, flags...)
				}
			}

			appArgs = append(appArgs, test.cmdName)

			err := cmd.Run(buildTestContext(t), appArgs)
			if test.errNotExpected {
				assert.NoError(t, err)
			} else {
				assert.Error(t, err)
			}
		})
	}
}

func TestCommand_FlagsFromExtPackage(t *testing.T) {
	var someint int
	flag.IntVar(&someint, "epflag", 2, "ext package flag usage")

	// Based on source code we can reset the global flag parsing this way
	defer func() {
		flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	}()

	cmd := &Command{
		AllowExtFlags: true,
		Flags: []Flag{
			&StringFlag{
				Name:     "carly",
				Aliases:  []string{"c"},
				Required: false,
			},
			&BoolFlag{
				Name:     "jimbob",
				Aliases:  []string{"j"},
				Required: false,
				Value:    true,
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "-c", "cly", "--epflag", "10"})
	assert.NoError(t, err)

	assert.Equal(t, int(10), someint)
	// this exercises the extFlag.Get()
	assert.Equal(t, int(10), cmd.Value("epflag"))

	cmd = &Command{
		Flags: []Flag{
			&StringFlag{
				Name:     "carly",
				Aliases:  []string{"c"},
				Required: false,
			},
			&BoolFlag{
				Name:     "jimbob",
				Aliases:  []string{"j"},
				Required: false,
				Value:    true,
			},
		},
	}

	// this should return an error since epflag shouldnt be registered
	err = cmd.Run(buildTestContext(t), []string{"foo", "-c", "cly", "--epflag", "10"})
	assert.Error(t, err)
}

func TestCommand_Setup_defaultsReader(t *testing.T) {
	cmd := &Command{}
	cmd.setupDefaults([]string{"test"})
	assert.Equal(t, cmd.Reader, os.Stdin)
}

func TestCommand_Setup_defaultsWriter(t *testing.T) {
	cmd := &Command{}
	cmd.setupDefaults([]string{"test"})
	assert.Equal(t, cmd.Writer, os.Stdout)
}

func TestCommand_CommandWithFlagBeforeTerminator(t *testing.T) {
	var parsedOption string
	var args Args

	cmd := &Command{
		Commands: []*Command{
			{
				Name: "cmd",
				Flags: []Flag{
					&StringFlag{Name: "option", Value: "", Usage: "some option"},
				},
				Action: func(_ context.Context, cmd *Command) error {
					parsedOption = cmd.String("option")
					args = cmd.Args()
					return nil
				},
			},
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"", "cmd", "--option", "my-option", "my-arg", "--", "--notARealFlag"}))

	require.Equal(t, "my-option", parsedOption)
	require.Equal(t, "my-arg", args.Get(0))
	require.Equal(t, "--notARealFlag", args.Get(1))
}

func TestCommand_CommandWithDash(t *testing.T) {
	var args Args

	cmd := &Command{
		Commands: []*Command{
			{
				Name: "cmd",
				Action: func(_ context.Context, cmd *Command) error {
					args = cmd.Args()
					return nil
				},
			},
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"", "cmd", "my-arg", "-"}))
	require.NotNil(t, args)
	require.Equal(t, "my-arg", args.Get(0))
	require.Equal(t, "-", args.Get(1))
}

func TestCommand_CommandWithNoFlagBeforeTerminator(t *testing.T) {
	var args Args

	cmd := &Command{
		Commands: []*Command{
			{
				Name: "cmd",
				Action: func(_ context.Context, cmd *Command) error {
					args = cmd.Args()
					return nil
				},
			},
		},
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}))

	require.NotNil(t, args)
	require.Equal(t, "my-arg", args.Get(0))
	require.Equal(t, "notAFlagAtAll", args.Get(1))
}

func TestCommand_SkipFlagParsing(t *testing.T) {
	var args Args

	cmd := &Command{
		SkipFlagParsing: true,
		Action: func(_ context.Context, cmd *Command) error {
			args = cmd.Args()
			return nil
		},
	}

	_ = cmd.Run(buildTestContext(t), []string{"", "--", "my-arg", "notAFlagAtAll"})

	assert.NotNil(t, args)
	assert.Equal(t, "--", args.Get(0))
	assert.Equal(t, "my-arg", args.Get(1))
	assert.Equal(t, "notAFlagAtAll", args.Get(2))
}

func TestCommand_VisibleCommands(t *testing.T) {
	cmd := &Command{
		Commands: []*Command{
			{
				Name:   "frob",
				Action: func(context.Context, *Command) error { return nil },
			},
			{
				Name:   "frib",
				Hidden: true,
				Action: func(context.Context, *Command) error { return nil },
			},
		},
	}

	cmd.setupDefaults([]string{"test"})
	expected := []*Command{
		cmd.Commands[0],
	}
	actual := cmd.VisibleCommands()
	assert.Len(t, actual, len(expected))
	for i, actualCommand := range actual {
		expectedCommand := expected[i]

		if expectedCommand.Action != nil {
			// comparing func addresses is OK!
			assert.Equal(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
		}

		func() {
			// nil out funcs, as they cannot be compared
			// (https://github.com/golang/go/issues/8554)
			expectedAction := expectedCommand.Action
			actualAction := actualCommand.Action
			defer func() {
				expectedCommand.Action = expectedAction
				actualCommand.Action = actualAction
			}()
			expectedCommand.Action = nil
			actualCommand.Action = nil

			assert.Equal(t, expectedCommand, actualCommand)
		}()
	}
}

func TestCommand_UseShortOptionHandling(t *testing.T) {
	var one, two bool
	var name string
	expected := "expectedName"

	cmd := buildMinimalTestCommand()
	cmd.UseShortOptionHandling = true
	cmd.Flags = []Flag{
		&BoolFlag{Name: "one", Aliases: []string{"o"}},
		&BoolFlag{Name: "two", Aliases: []string{"t"}},
		&StringFlag{Name: "name", Aliases: []string{"n"}},
	}
	cmd.Action = func(_ context.Context, cmd *Command) error {
		one = cmd.Bool("one")
		two = cmd.Bool("two")
		name = cmd.String("name")
		return nil
	}

	_ = cmd.Run(buildTestContext(t), []string{"", "-on", expected})
	assert.True(t, one)
	assert.False(t, two)
	assert.Equal(t, name, expected)
}

func TestCommand_UseShortOptionHandling_missing_value(t *testing.T) {
	cmd := buildMinimalTestCommand()
	cmd.UseShortOptionHandling = true
	cmd.Flags = []Flag{
		&StringFlag{Name: "name", Aliases: []string{"n"}},
	}

	err := cmd.Run(buildTestContext(t), []string{"", "-n"})
	assert.EqualError(t, err, "flag needs an argument: -n")
}

func TestCommand_UseShortOptionHandlingCommand(t *testing.T) {
	var (
		one, two bool
		name     string
		expected = "expectedName"
	)

	cmd := &Command{
		Name: "cmd",
		Flags: []Flag{
			&BoolFlag{Name: "one", Aliases: []string{"o"}},
			&BoolFlag{Name: "two", Aliases: []string{"t"}},
			&StringFlag{Name: "name", Aliases: []string{"n"}},
		},
		Action: func(_ context.Context, cmd *Command) error {
			one = cmd.Bool("one")
			two = cmd.Bool("two")
			name = cmd.String("name")
			return nil
		},
		UseShortOptionHandling: true,
		Writer:                 io.Discard,
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"cmd", "-on", expected}))
	require.True(t, one)
	require.False(t, two)
	require.Equal(t, expected, name)
}

func TestCommand_UseShortOptionHandlingCommand_missing_value(t *testing.T) {
	cmd := buildMinimalTestCommand()
	cmd.UseShortOptionHandling = true
	command := &Command{
		Name: "cmd",
		Flags: []Flag{
			&StringFlag{Name: "name", Aliases: []string{"n"}},
		},
	}
	cmd.Commands = []*Command{command}

	require.EqualError(
		t,
		cmd.Run(buildTestContext(t), []string{"", "cmd", "-n"}),
		"flag needs an argument: -n",
	)
}

func TestCommand_UseShortOptionHandlingSubCommand(t *testing.T) {
	var one, two bool
	var name string

	cmd := buildMinimalTestCommand()
	cmd.UseShortOptionHandling = true
	cmd.Commands = []*Command{
		{
			Name: "cmd",
			Commands: []*Command{
				{
					Name: "sub",
					Flags: []Flag{
						&BoolFlag{Name: "one", Aliases: []string{"o"}},
						&BoolFlag{Name: "two", Aliases: []string{"t"}},
						&StringFlag{Name: "name", Aliases: []string{"n"}},
					},
					Action: func(_ context.Context, cmd *Command) error {
						one = cmd.Bool("one")
						two = cmd.Bool("two")
						name = cmd.String("name")
						return nil
					},
				},
			},
		},
	}

	expected := "expectedName"

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"", "cmd", "sub", "-on", expected}))
	require.True(t, one)
	require.False(t, two)
	require.Equal(t, expected, name)
}

func TestCommand_UseShortOptionHandlingSubCommand_missing_value(t *testing.T) {
	cmd := buildMinimalTestCommand()
	cmd.UseShortOptionHandling = true
	command := &Command{
		Name: "cmd",
	}
	subCommand := &Command{
		Name: "sub",
		Flags: []Flag{
			&StringFlag{Name: "name", Aliases: []string{"n"}},
		},
	}
	command.Commands = []*Command{subCommand}
	cmd.Commands = []*Command{command}

	err := cmd.Run(buildTestContext(t), []string{"", "cmd", "sub", "-n"})
	assert.EqualError(t, err, "flag needs an argument: -n")
}

func TestCommand_UseShortOptionAfterSliceFlag(t *testing.T) {
	var one, two bool
	var name string
	var sliceValDest []string
	var sliceVal []string
	expected := "expectedName"

	cmd := buildMinimalTestCommand()
	cmd.UseShortOptionHandling = true
	cmd.Flags = []Flag{
		&StringSliceFlag{Name: "env", Aliases: []string{"e"}, Destination: &sliceValDest},
		&BoolFlag{Name: "one", Aliases: []string{"o"}},
		&BoolFlag{Name: "two", Aliases: []string{"t"}},
		&StringFlag{Name: "name", Aliases: []string{"n"}},
	}
	cmd.Action = func(_ context.Context, cmd *Command) error {
		sliceVal = cmd.StringSlice("env")
		one = cmd.Bool("one")
		two = cmd.Bool("two")
		name = cmd.String("name")
		return nil
	}

	_ = cmd.Run(buildTestContext(t), []string{"", "-e", "foo", "-on", expected})
	assert.Equal(t, sliceVal, []string{"foo"})
	assert.Equal(t, sliceValDest, []string{"foo"})
	assert.True(t, one)
	assert.False(t, two)
	assert.Equal(t, expected, name)
}

func TestCommand_UseShortOptionWithArg(t *testing.T) {
	var rootPath string
	cmd := &Command{
		UseShortOptionHandling: true,
		Commands: []*Command{
			{
				Name:  "short",
				Usage: "complete a task on the list",
				Arguments: []Argument{
					&StringArg{Name: "root", UsageText: "Root path", Destination: &rootPath},
				},
				Flags: []Flag{
					&BoolFlag{Name: "serve", Aliases: []string{"s"}},
					&BoolFlag{Name: "option", Aliases: []string{"o"}},
					&StringFlag{Name: "message", Aliases: []string{"m"}},
				},
				Action: func(ctx context.Context, cmd *Command) error {
					return nil
				},
			},
		},
	}
	err := cmd.Run(buildTestContext(t), []string{"app", "short", "-som", "hello", "/path/to/root"})
	require.NoError(t, err)
	require.Equal(t, "/path/to/root", rootPath)
}

func TestCommand_Float64Flag(t *testing.T) {
	var meters float64

	cmd := &Command{
		Flags: []Flag{
			&FloatFlag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
		},
		Action: func(_ context.Context, cmd *Command) error {
			meters = cmd.Float("height")
			return nil
		},
	}

	_ = cmd.Run(buildTestContext(t), []string{"", "--height", "1.93"})
	assert.Equal(t, 1.93, meters)
}

func TestCommand_ParseSliceFlags(t *testing.T) {
	var parsedIntSlice []int64
	var parsedStringSlice []string

	cmd := &Command{
		Commands: []*Command{
			{
				Name: "cmd",
				Flags: []Flag{
					&Int64SliceFlag{Name: "p", Value: []int64{}, Usage: "set one or more ip addr"},
					&StringSliceFlag{Name: "ip", Value: []string{}, Usage: "set one or more ports to open"},
				},
				Action: func(_ context.Context, cmd *Command) error {
					parsedIntSlice = cmd.Int64Slice("p")
					parsedStringSlice = cmd.StringSlice("ip")
					return nil
				},
			},
		},
	}

	r := require.New(t)

	r.NoError(cmd.Run(buildTestContext(t), []string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"}))
	r.Equal([]int64{22, 80}, parsedIntSlice)
	r.Equal([]string{"8.8.8.8", "8.8.4.4"}, parsedStringSlice)
}

func TestCommand_ParseSliceFlagsWithMissingValue(t *testing.T) {
	var parsedIntSlice []int64
	var parsedStringSlice []string

	cmd := &Command{
		Commands: []*Command{
			{
				Name: "cmd",
				Flags: []Flag{
					&Int64SliceFlag{Name: "a", Usage: "set numbers"},
					&StringSliceFlag{Name: "str", Usage: "set strings"},
				},
				Action: func(_ context.Context, cmd *Command) error {
					parsedIntSlice = cmd.Int64Slice("a")
					parsedStringSlice = cmd.StringSlice("str")
					return nil
				},
			},
		},
	}

	r := require.New(t)

	r.NoError(cmd.Run(buildTestContext(t), []string{"", "cmd", "-a", "2", "-str", "A"}))
	r.Equal([]int64{2}, parsedIntSlice)
	r.Equal([]string{"A"}, parsedStringSlice)
}

func TestCommand_DefaultStdin(t *testing.T) {
	cmd := &Command{}
	cmd.setupDefaults([]string{"test"})

	assert.Equal(t, cmd.Reader, os.Stdin, "Default input reader not set.")
}

func TestCommand_DefaultStdout(t *testing.T) {
	cmd := &Command{}
	cmd.setupDefaults([]string{"test"})

	assert.Equal(t, cmd.Writer, os.Stdout, "Default output writer not set.")
}

func TestCommand_SetStdin(t *testing.T) {
	buf := make([]byte, 12)

	cmd := &Command{
		Name:   "test",
		Reader: strings.NewReader("Hello World!"),
		Action: func(_ context.Context, cmd *Command) error {
			_, err := cmd.Reader.Read(buf)
			return err
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"help"})
	require.NoError(t, err)
	assert.Equal(t, "Hello World!", string(buf), "Command did not read input from desired reader.")
}

func TestCommand_SetStdin_Subcommand(t *testing.T) {
	buf := make([]byte, 12)

	cmd := &Command{
		Name:   "test",
		Reader: strings.NewReader("Hello World!"),
		Commands: []*Command{
			{
				Name: "command",
				Commands: []*Command{
					{
						Name: "subcommand",
						Action: func(_ context.Context, cmd *Command) error {
							_, err := cmd.Root().Reader.Read(buf)
							return err
						},
					},
				},
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"test", "command", "subcommand"})
	require.NoError(t, err)
	assert.Equal(t, "Hello World!", string(buf), "Command did not read input from desired reader.")
}

func TestCommand_SetStdout(t *testing.T) {
	var w bytes.Buffer

	cmd := &Command{
		Name:   "test",
		Writer: &w,
	}

	err := cmd.Run(buildTestContext(t), []string{"help"})
	require.NoError(t, err)
	assert.NotZero(t, w.Len(), "Command did not write output to desired writer.")
}

func TestCommand_BeforeFunc(t *testing.T) {
	counts := &opCounts{}
	beforeError := fmt.Errorf("fail")
	var err error

	cmd := &Command{
		Before: func(_ context.Context, cmd *Command) (context.Context, error) {
			counts.Total++
			counts.Before = counts.Total
			s := cmd.String("opt")
			if s == "fail" {
				return nil, beforeError
			}

			return nil, nil
		},
		Commands: []*Command{
			{
				Name: "sub",
				Action: func(context.Context, *Command) error {
					counts.Total++
					counts.SubCommand = counts.Total
					return nil
				},
			},
		},
		Flags: []Flag{
			&StringFlag{Name: "opt"},
		},
		Writer: io.Discard,
	}

	// run with the Before() func succeeding
	err = cmd.Run(buildTestContext(t), []string{"command", "--opt", "succeed", "sub"})
	require.NoError(t, err)

	assert.Equal(t, 1, counts.Before, "Before() not executed when expected")
	assert.Equal(t, 2, counts.SubCommand, "Subcommand not executed when expected")

	// reset
	counts = &opCounts{}

	// run with the Before() func failing
	err = cmd.Run(buildTestContext(t), []string{"command", "--opt", "fail", "sub"})

	// should be the same error produced by the Before func
	assert.ErrorIs(t, err, beforeError, "Run error expected, but not received")
	assert.Equal(t, 1, counts.Before, "Before() not executed when expected")
	assert.Equal(t, 0, counts.SubCommand, "Subcommand executed when NOT expected")

	// reset
	counts = &opCounts{}

	afterError := errors.New("fail again")
	cmd.After = func(context.Context, *Command) error {
		return afterError
	}

	// run with the Before() func failing, wrapped by After()
	err = cmd.Run(buildTestContext(t), []string{"command", "--opt", "fail", "sub"})

	// should be the same error produced by the Before func
	if _, ok := err.(MultiError); !ok {
		t.Errorf("MultiError expected, but not received")
	}

	assert.Equal(t, 1, counts.Before, "Before() not executed when expected")
	assert.Zero(t, counts.SubCommand, "Subcommand executed when NOT expected")
}

func TestCommand_BeforeFuncPersistentFlag(t *testing.T) {
	counts := &opCounts{}
	beforeError := fmt.Errorf("fail")
	var err error

	cmd := &Command{
		Before: func(_ context.Context, cmd *Command) (context.Context, error) {
			counts.Before++
			s := cmd.String("opt")
			if s != "value" {
				return nil, beforeError
			}
			return nil, nil
		},
		Commands: []*Command{
			{
				Name: "sub",
				Action: func(context.Context, *Command) error {
					counts.SubCommand++
					return nil
				},
			},
		},
		Flags: []Flag{
			&StringFlag{Name: "opt"},
		},
		Writer: io.Discard,
	}

	// Check that --opt value is available in root command Before hook,
	// even when it was set on the subcommand.
	err = cmd.Run(buildTestContext(t), []string{"command", "sub", "--opt", "value"})
	require.NoError(t, err)
	assert.Equal(t, 1, counts.Before, "Before() not executed when expected")
	assert.Equal(t, 1, counts.SubCommand, "Subcommand not executed when expected")
}

func TestCommand_BeforeAfterFuncShellCompletion(t *testing.T) {
	t.Skip("TODO: is '--generate-shell-completion' (flag) still supported?")

	counts := &opCounts{}

	cmd := &Command{
		EnableShellCompletion: true,
		Before: func(context.Context, *Command) (context.Context, error) {
			counts.Total++
			counts.Before = counts.Total
			return nil, nil
		},
		After: func(context.Context, *Command) error {
			counts.Total++
			counts.After = counts.Total
			return nil
		},
		Commands: []*Command{
			{
				Name: "sub",
				Action: func(context.Context, *Command) error {
					counts.Total++
					counts.SubCommand = counts.Total
					return nil
				},
			},
		},
		Flags: []Flag{
			&StringFlag{Name: "opt"},
		},
		Writer: io.Discard,
	}

	r := require.New(t)

	// run with the Before() func succeeding
	r.NoError(
		cmd.Run(
			buildTestContext(t),
			[]string{
				"command",
				"--opt", "succeed",
				"sub", completionFlag,
			},
		),
	)

	r.Equalf(0, counts.Before, "Before was run")
	r.Equal(0, counts.After, "After was run")
	r.Equal(0, counts.SubCommand, "SubCommand was run")
}

func TestCommand_AfterFunc(t *testing.T) {
	counts := &opCounts{}
	afterError := fmt.Errorf("fail")
	var err error

	cmd := &Command{
		After: func(_ context.Context, cmd *Command) error {
			counts.Total++
			counts.After = counts.Total
			s := cmd.String("opt")
			if s == "fail" {
				return afterError
			}

			return nil
		},
		Commands: []*Command{
			{
				Name: "sub",
				Action: func(context.Context, *Command) error {
					counts.Total++
					counts.SubCommand = counts.Total
					return nil
				},
			},
		},
		Flags: []Flag{
			&StringFlag{Name: "opt"},
		},
	}

	// run with the After() func succeeding
	err = cmd.Run(buildTestContext(t), []string{"command", "--opt", "succeed", "sub"})
	require.NoError(t, err)
	assert.Equal(t, 2, counts.After, "After() not executed when expected")
	assert.Equal(t, 1, counts.SubCommand, "Subcommand not executed when expected")

	// reset
	counts = &opCounts{}

	// run with the Before() func failing
	err = cmd.Run(buildTestContext(t), []string{"command", "--opt", "fail", "sub"})

	// should be the same error produced by the Before func
	assert.ErrorIs(t, err, afterError, "Run error expected, but not received")
	assert.Equal(t, 2, counts.After, "After() not executed when expected")
	assert.Equal(t, 1, counts.SubCommand, "Subcommand not executed when expected")

	/*
		reset
	*/
	counts = &opCounts{}
	// reset the flags since they are set previously
	cmd.Flags = []Flag{
		&StringFlag{Name: "opt"},
	}

	// run with none args
	err = cmd.Run(buildTestContext(t), []string{"command"})

	// should be the same error produced by the Before func
	require.NoError(t, err)

	assert.Equal(t, 1, counts.After, "After() not executed when expected")
	assert.Equal(t, 0, counts.SubCommand, "Subcommand not executed when expected")
}

func TestCommandNoHelpFlag(t *testing.T) {
	oldFlag := HelpFlag
	defer func() {
		HelpFlag = oldFlag
	}()

	HelpFlag = nil

	cmd := &Command{Writer: io.Discard}

	err := cmd.Run(buildTestContext(t), []string{"test", "-h"})

	assert.ErrorContains(t, err, providedButNotDefinedErrMsg, "expected error about missing help flag")
}

func TestRequiredFlagCommandRunBehavior(t *testing.T) {
	tdata := []struct {
		testCase        string
		appFlags        []Flag
		appRunInput     []string
		appCommands     []*Command
		expectedAnError bool
	}{
		// assertion: empty input, when a required flag is present, errors
		{
			testCase:        "error_case_empty_input_with_required_flag_on_app",
			appRunInput:     []string{"myCLI"},
			appFlags:        []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
			expectedAnError: true,
		},
		{
			testCase:    "error_case_empty_input_with_required_flag_on_command",
			appRunInput: []string{"myCLI", "myCommand"},
			appCommands: []*Command{{
				Name:  "myCommand",
				Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
			}},
			expectedAnError: true,
		},
		{
			testCase:    "error_case_empty_input_with_required_flag_on_subcommand",
			appRunInput: []string{"myCLI", "myCommand", "mySubCommand"},
			appCommands: []*Command{{
				Name: "myCommand",
				Commands: []*Command{{
					Name:  "mySubCommand",
					Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
				}},
			}},
			expectedAnError: true,
		},
		// assertion: inputting --help, when a required flag is present, does not error
		{
			testCase:    "valid_case_help_input_with_required_flag_on_app",
			appRunInput: []string{"myCLI", "--help"},
			appFlags:    []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
		},
		{
			testCase:    "valid_case_help_input_with_required_flag_on_command",
			appRunInput: []string{"myCLI", "myCommand", "--help"},
			appCommands: []*Command{{
				Name:  "myCommand",
				Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
			}},
		},
		{
			testCase:    "valid_case_help_input_with_required_flag_on_subcommand",
			appRunInput: []string{"myCLI", "myCommand", "mySubCommand", "--help"},
			appCommands: []*Command{{
				Name: "myCommand",
				Commands: []*Command{{
					Name:  "mySubCommand",
					Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
				}},
			}},
		},
		// assertion: giving optional input, when a required flag is present, errors
		{
			testCase:        "error_case_optional_input_with_required_flag_on_app",
			appRunInput:     []string{"myCLI", "--optional", "cats"},
			appFlags:        []Flag{&StringFlag{Name: "requiredFlag", Required: true}, &StringFlag{Name: "optional"}},
			expectedAnError: true,
		},
		{
			testCase:    "error_case_optional_input_with_required_flag_on_command",
			appRunInput: []string{"myCLI", "myCommand", "--optional", "cats"},
			appCommands: []*Command{{
				Name:  "myCommand",
				Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}, &StringFlag{Name: "optional"}},
			}},
			expectedAnError: true,
		},
		{
			testCase:    "error_case_optional_input_with_required_flag_on_subcommand",
			appRunInput: []string{"myCLI", "myCommand", "mySubCommand", "--optional", "cats"},
			appCommands: []*Command{{
				Name: "myCommand",
				Commands: []*Command{{
					Name:  "mySubCommand",
					Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}, &StringFlag{Name: "optional"}},
				}},
			}},
			expectedAnError: true,
		},
		// assertion: when a required flag is present, inputting that required flag does not error
		{
			testCase:    "valid_case_required_flag_input_on_app",
			appRunInput: []string{"myCLI", "--requiredFlag", "cats"},
			appFlags:    []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
		},
		{
			testCase:    "valid_case_required_flag_input_on_command",
			appRunInput: []string{"myCLI", "myCommand", "--requiredFlag", "cats"},
			appCommands: []*Command{{
				Name:  "myCommand",
				Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
			}},
		},
		{
			testCase:    "valid_case_required_flag_input_on_subcommand",
			appRunInput: []string{"myCLI", "myCommand", "mySubCommand", "--requiredFlag", "cats"},
			appCommands: []*Command{{
				Name: "myCommand",
				Commands: []*Command{{
					Name:  "mySubCommand",
					Flags: []Flag{&StringFlag{Name: "requiredFlag", Required: true}},
					Action: func(context.Context, *Command) error {
						return nil
					},
				}},
			}},
		},
	}
	for _, test := range tdata {
		t.Run(test.testCase, func(t *testing.T) {
			// setup
			cmd := buildMinimalTestCommand()
			cmd.Flags = test.appFlags
			cmd.Commands = test.appCommands

			// logic under test
			err := cmd.Run(buildTestContext(t), test.appRunInput)

			// assertions
			if test.expectedAnError {
				assert.Error(t, err)
				if _, ok := err.(requiredFlagsErr); test.expectedAnError && !ok {
					t.Errorf("expected a requiredFlagsErr, but got: %s", err)
				}
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestCommandHelpPrinter(t *testing.T) {
	oldPrinter := HelpPrinter
	defer func() {
		HelpPrinter = oldPrinter
	}()

	wasCalled := false
	HelpPrinter = func(io.Writer, string, interface{}) {
		wasCalled = true
	}

	cmd := &Command{}

	_ = cmd.Run(buildTestContext(t), []string{"-h"})

	assert.True(t, wasCalled, "Help printer expected to be called, but was not")
}

func TestCommand_VersionPrinter(t *testing.T) {
	oldPrinter := VersionPrinter
	defer func() {
		VersionPrinter = oldPrinter
	}()

	wasCalled := false
	VersionPrinter = func(*Command) {
		wasCalled = true
	}

	cmd := &Command{}
	ShowVersion(cmd)

	assert.True(t, wasCalled, "Version printer expected to be called, but was not")
}

func TestCommand_CommandNotFound(t *testing.T) {
	counts := &opCounts{}
	cmd := &Command{
		CommandNotFound: func(context.Context, *Command, string) {
			counts.Total++
			counts.CommandNotFound = counts.Total
		},
		Commands: []*Command{
			{
				Name: "bar",
				Action: func(context.Context, *Command) error {
					counts.Total++
					counts.SubCommand = counts.Total
					return nil
				},
			},
		},
	}

	_ = cmd.Run(buildTestContext(t), []string{"command", "foo"})

	assert.Equal(t, 1, counts.CommandNotFound)
	assert.Equal(t, 0, counts.SubCommand)
	assert.Equal(t, 1, counts.Total)
}

func TestCommand_OrderOfOperations(t *testing.T) {
	buildCmdCounts := func() (*Command, *opCounts) {
		counts := &opCounts{}

		cmd := &Command{
			EnableShellCompletion: true,
			ShellComplete: func(context.Context, *Command) {
				counts.Total++
				counts.ShellComplete = counts.Total
			},
			OnUsageError: func(context.Context, *Command, error, bool) error {
				counts.Total++
				counts.OnUsageError = counts.Total
				return errors.New("hay OnUsageError")
			},
			Writer: io.Discard,
		}

		beforeNoError := func(context.Context, *Command) (context.Context, error) {
			counts.Total++
			counts.Before = counts.Total
			return nil, nil
		}

		cmd.Before = beforeNoError
		cmd.CommandNotFound = func(context.Context, *Command, string) {
			counts.Total++
			counts.CommandNotFound = counts.Total
		}

		afterNoError := func(context.Context, *Command) error {
			counts.Total++
			counts.After = counts.Total
			return nil
		}

		cmd.After = afterNoError
		cmd.Commands = []*Command{
			{
				Name: "bar",
				Action: func(context.Context, *Command) error {
					counts.Total++
					counts.SubCommand = counts.Total
					return nil
				},
			},
		}

		cmd.Action = func(context.Context, *Command) error {
			counts.Total++
			counts.Action = counts.Total
			return nil
		}

		return cmd, counts
	}

	t.Run("on usage error", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		r := require.New(t)

		_ = cmd.Run(buildTestContext(t), []string{"command", "--nope"})
		r.Equal(1, counts.OnUsageError)
		r.Equal(1, counts.Total)
	})

	t.Run("shell complete", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		r := require.New(t)

		_ = cmd.Run(buildTestContext(t), []string{"command", completionFlag})
		r.Equal(1, counts.ShellComplete)
		r.Equal(1, counts.Total)
	})

	t.Run("nil on usage error", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		cmd.OnUsageError = nil

		_ = cmd.Run(buildTestContext(t), []string{"command", "--nope"})
		require.Equal(t, 0, counts.Total)
	})

	t.Run("before after action hooks", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		r := require.New(t)

		_ = cmd.Run(buildTestContext(t), []string{"command", "foo"})
		r.Equal(0, counts.OnUsageError)
		r.Equal(1, counts.Before)
		r.Equal(0, counts.CommandNotFound)
		r.Equal(2, counts.Action)
		r.Equal(3, counts.After)
		r.Equal(3, counts.Total)
	})

	t.Run("before with error", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		cmd.Before = func(context.Context, *Command) (context.Context, error) {
			counts.Total++
			counts.Before = counts.Total
			return nil, errors.New("hay Before")
		}

		r := require.New(t)

		_ = cmd.Run(buildTestContext(t), []string{"command", "bar"})
		r.Equal(0, counts.OnUsageError)
		r.Equal(1, counts.Before)
		r.Equal(2, counts.After)
		r.Equal(2, counts.Total)
	})

	t.Run("nil after", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		cmd.After = nil
		r := require.New(t)

		_ = cmd.Run(buildTestContext(t), []string{"command", "bar"})
		r.Equal(0, counts.OnUsageError)
		r.Equal(1, counts.Before)
		r.Equal(2, counts.SubCommand)
		r.Equal(2, counts.Total)
	})

	t.Run("after errors", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		cmd.After = func(context.Context, *Command) error {
			counts.Total++
			counts.After = counts.Total
			return errors.New("hay After")
		}

		r := require.New(t)

		err := cmd.Run(buildTestContext(t), []string{"command", "bar"})
		r.Error(err)
		r.Equal(0, counts.OnUsageError)
		r.Equal(1, counts.Before)
		r.Equal(2, counts.SubCommand)
		r.Equal(3, counts.After)
		r.Equal(3, counts.Total)
	})

	t.Run("nil commands", func(t *testing.T) {
		cmd, counts := buildCmdCounts()
		cmd.Commands = nil
		r := require.New(t)

		_ = cmd.Run(buildTestContext(t), []string{"command"})
		r.Equal(0, counts.OnUsageError)
		r.Equal(1, counts.Before)
		r.Equal(2, counts.Action)
		r.Equal(3, counts.After)
		r.Equal(3, counts.Total)
	})
}

func TestCommand_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
	subcommandHelpTopics := [][]string{
		{"foo", "--help"},
		{"foo", "-h"},
		{"foo", "help"},
	}

	for _, flagSet := range subcommandHelpTopics {
		t.Run(fmt.Sprintf("checking with flags %v", flagSet), func(t *testing.T) {
			buf := new(bytes.Buffer)

			subCmdBar := &Command{
				Name:  "bar",
				Usage: "does bar things",
			}
			subCmdBaz := &Command{
				Name:  "baz",
				Usage: "does baz things",
			}
			cmd := &Command{
				Name:        "foo",
				Description: "descriptive wall of text about how it does foo things",
				Commands:    []*Command{subCmdBar, subCmdBaz},
				Action:      func(context.Context, *Command) error { return nil },
				Writer:      buf,
			}

			err := cmd.Run(buildTestContext(t), flagSet)
			assert.NoError(t, err)

			output := buf.String()

			assert.NotContains(t, output, "No help topic for", "expect a help topic, got none")

			for _, shouldContain := range []string{
				cmd.Name, cmd.Description,
				subCmdBar.Name, subCmdBar.Usage,
				subCmdBaz.Name, subCmdBaz.Usage,
			} {
				assert.Contains(t, output, shouldContain, "want help to contain %q, did not: \n%q", shouldContain, output)
			}
		})
	}
}

func TestCommand_Run_SubcommandFullPath(t *testing.T) {
	out := &bytes.Buffer{}

	subCmd := &Command{
		Name:      "bar",
		Usage:     "does bar things",
		ArgsUsage: "[arguments...]",
	}

	cmd := &Command{
		Name:        "foo",
		Description: "foo commands",
		Commands:    []*Command{subCmd},
		Writer:      out,
	}

	require.NoError(t, cmd.Run(buildTestContext(t), []string{"foo", "bar", "--help"}))

	outString := out.String()
	require.Contains(t, outString, "foo bar - does bar things")
	require.Contains(t, outString, "foo bar [options] [arguments...]")
}

func TestCommand_Run_Help(t *testing.T) {
	tests := []struct {
		helpArguments []string
		hideHelp      bool
		wantContains  string
		wantErr       error
	}{
		{
			helpArguments: []string{"boom", "--help"},
			hideHelp:      false,
			wantContains:  "boom - make an explosive entrance",
		},
		{
			helpArguments: []string{"boom", "-h"},
			hideHelp:      false,
			wantContains:  "boom - make an explosive entrance",
		},
		{
			helpArguments: []string{"boom", "help"},
			hideHelp:      false,
			wantContains:  "boom - make an explosive entrance",
		},
		{
			helpArguments: []string{"boom", "--help"},
			hideHelp:      true,
			wantErr:       fmt.Errorf("flag provided but not defined: -help"),
		},
		{
			helpArguments: []string{"boom", "-h"},
			hideHelp:      true,
			wantErr:       fmt.Errorf("flag provided but not defined: -h"),
		},
		{
			helpArguments: []string{"boom", "help"},
			hideHelp:      true,
			wantContains:  "boom I say!",
		},
	}

	for _, tt := range tests {
		t.Run(fmt.Sprintf("checking with arguments %v%v", tt.helpArguments, tt.hideHelp), func(t *testing.T) {
			buf := new(bytes.Buffer)

			cmd := &Command{
				Name:     "boom",
				Usage:    "make an explosive entrance",
				Writer:   buf,
				HideHelp: tt.hideHelp,
				Action: func(context.Context, *Command) error {
					buf.WriteString("boom I say!")
					return nil
				},
			}

			err := cmd.Run(buildTestContext(t), tt.helpArguments)
			if tt.wantErr != nil {
				assert.ErrorContains(t, err, tt.wantErr.Error())
			}

			output := buf.String()

			assert.Contains(t, output, tt.wantContains, "want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
		})
	}
}

func TestCommand_Run_Version(t *testing.T) {
	versionArguments := [][]string{{"boom", "--version"}, {"boom", "-v"}}

	for _, args := range versionArguments {
		t.Run(fmt.Sprintf("checking with arguments %v", args), func(t *testing.T) {
			buf := new(bytes.Buffer)

			cmd := &Command{
				Name:    "boom",
				Usage:   "make an explosive entrance",
				Version: "0.1.0",
				Writer:  buf,
				Action: func(context.Context, *Command) error {
					buf.WriteString("boom I say!")
					return nil
				},
			}

			err := cmd.Run(buildTestContext(t), args)
			assert.NoError(t, err)
			assert.Contains(t, buf.String(), "0.1.0", "want version to contain 0.1.0")
		})
	}
}

func TestCommand_Run_Categories(t *testing.T) {
	buf := new(bytes.Buffer)

	cmd := &Command{
		Name:     "categories",
		HideHelp: true,
		Commands: []*Command{
			{
				Name:     "command1",
				Category: "1",
			},
			{
				Name:     "command2",
				Category: "1",
			},
			{
				Name:     "command3",
				Category: "2",
			},
		},
		Writer: buf,
	}

	_ = cmd.Run(buildTestContext(t), []string{"categories"})

	expect := commandCategories([]*commandCategory{
		{
			name: "1",
			commands: []*Command{
				cmd.Commands[0],
				cmd.Commands[1],
			},
		},
		{
			name: "2",
			commands: []*Command{
				cmd.Commands[2],
			},
		},
	})

	require.Equal(t, &expect, cmd.categories)

	output := buf.String()

	assert.Contains(t, output, "1:\n     command1", "want buffer to include category %q, did not: \n%q", "1:\n     command1", output)
}

func TestCommand_VisibleCategories(t *testing.T) {
	cmd := &Command{
		Name:     "visible-categories",
		HideHelp: true,
		Commands: []*Command{
			{
				Name:     "command1",
				Category: "1",
				Hidden:   true,
			},
			{
				Name:     "command2",
				Category: "2",
			},
			{
				Name:     "command3",
				Category: "3",
			},
		},
	}

	expected := []CommandCategory{
		&commandCategory{
			name: "2",
			commands: []*Command{
				cmd.Commands[1],
			},
		},
		&commandCategory{
			name: "3",
			commands: []*Command{
				cmd.Commands[2],
			},
		},
	}

	cmd.setupDefaults([]string{"test"})
	assert.Equal(t, expected, cmd.VisibleCategories())

	cmd = &Command{
		Name:     "visible-categories",
		HideHelp: true,
		Commands: []*Command{
			{
				Name:     "command1",
				Category: "1",
				Hidden:   true,
			},
			{
				Name:     "command2",
				Category: "2",
				Hidden:   true,
			},
			{
				Name:     "command3",
				Category: "3",
			},
		},
	}

	expected = []CommandCategory{
		&commandCategory{
			name: "3",
			commands: []*Command{
				cmd.Commands[2],
			},
		},
	}

	cmd.setupDefaults([]string{"test"})
	assert.Equal(t, expected, cmd.VisibleCategories())

	cmd = &Command{
		Name:     "visible-categories",
		HideHelp: true,
		Commands: []*Command{
			{
				Name:     "command1",
				Category: "1",
				Hidden:   true,
			},
			{
				Name:     "command2",
				Category: "2",
				Hidden:   true,
			},
			{
				Name:     "command3",
				Category: "3",
				Hidden:   true,
			},
		},
	}

	cmd.setupDefaults([]string{"test"})
	assert.Empty(t, cmd.VisibleCategories())
}

func TestCommand_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
	cmd := &Command{
		Commands: []*Command{
			{
				Commands: []*Command{
					{
						Name: "sub",
					},
				},
				Name:   "bar",
				Before: func(context.Context, *Command) (context.Context, error) { return nil, fmt.Errorf("before error") },
				After:  func(context.Context, *Command) error { return fmt.Errorf("after error") },
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "bar"})
	assert.ErrorContains(t, err, "before error")
	assert.ErrorContains(t, err, "after error")
}

func TestCommand_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
	cmd := &Command{
		Flags: []Flag{
			&Int64Flag{Name: "flag"},
		},
		OnUsageError: func(_ context.Context, _ *Command, err error, isSubcommand bool) error {
			assert.False(t, isSubcommand, "Expect subcommand")
			assert.ErrorContains(t, err, "\"wrong\": invalid syntax")
			return errors.New("intercepted: " + err.Error())
		},
		Commands: []*Command{
			{
				Name: "bar",
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "--flag=wrong", "bar"})
	assert.ErrorContains(t, err, "parsing \"wrong\": invalid syntax", "Expect an intercepted error")
}

// A custom flag that conforms to the relevant interfaces, but has none of the
// fields that the other flag types do.
type customBoolFlag struct {
	Nombre string
}

// Don't use the normal FlagStringer
func (c *customBoolFlag) String() string {
	return "***" + c.Nombre + "***"
}

func (c *customBoolFlag) Names() []string {
	return []string{c.Nombre}
}

func (c *customBoolFlag) TakesValue() bool {
	return false
}

func (c *customBoolFlag) GetValue() string {
	return "value"
}

func (c *customBoolFlag) GetUsage() string {
	return "usage"
}

func (c *customBoolFlag) PreParse() error {
	return nil
}

func (c *customBoolFlag) PostParse() error {
	return nil
}

func (c *customBoolFlag) Get() any {
	dest := false
	return &boolValue{
		destination: &dest,
	}
}

func (c *customBoolFlag) Set(_, _ string) error {
	return nil
}

func (c *customBoolFlag) RunAction(context.Context, *Command) error {
	return nil
}

func (c *customBoolFlag) IsSet() bool {
	return false
}

func (c *customBoolFlag) IsRequired() bool {
	return false
}

func (c *customBoolFlag) IsVisible() bool {
	return false
}

func (c *customBoolFlag) GetCategory() string {
	return ""
}

func (c *customBoolFlag) GetEnvVars() []string {
	return nil
}

func (c *customBoolFlag) GetDefaultText() string {
	return ""
}

func TestCustomFlagsUnused(t *testing.T) {
	cmd := &Command{
		Flags:  []Flag{&customBoolFlag{"custom"}},
		Writer: io.Discard,
	}

	err := cmd.Run(buildTestContext(t), []string{"foo"})
	assert.NoError(t, err, "Run returned unexpected error")
}

func TestCustomFlagsUsed(t *testing.T) {
	cmd := &Command{
		Flags:  []Flag{&customBoolFlag{"custom"}},
		Writer: io.Discard,
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "--custom=bar"})
	assert.NoError(t, err, "Run returned unexpected error")
}

func TestCustomHelpVersionFlags(t *testing.T) {
	cmd := &Command{
		Writer: io.Discard,
	}

	// Be sure to reset the global flags
	defer func(helpFlag Flag, versionFlag Flag) {
		HelpFlag = helpFlag.(*BoolFlag)
		VersionFlag = versionFlag.(*BoolFlag)
	}(HelpFlag, VersionFlag)

	HelpFlag = &customBoolFlag{"help-custom"}
	VersionFlag = &customBoolFlag{"version-custom"}

	err := cmd.Run(buildTestContext(t), []string{"foo", "--help-custom=bar"})
	assert.NoError(t, err, "Run returned unexpected error")
}

func TestHandleExitCoder_Default(t *testing.T) {
	app := buildMinimalTestCommand()
	_ = app.handleExitCoder(context.Background(), Exit("Default Behavior Error", 42))

	output := fakeErrWriter.String()
	assert.Contains(t, output, "Default", "Expected Default Behavior from Error Handler")
}

func TestHandleExitCoder_Custom(t *testing.T) {
	cmd := buildMinimalTestCommand()

	cmd.ExitErrHandler = func(context.Context, *Command, error) {
		_, _ = fmt.Fprintln(ErrWriter, "I'm a Custom error handler, I print what I want!")
	}

	_ = cmd.handleExitCoder(context.Background(), Exit("Default Behavior Error", 42))

	output := fakeErrWriter.String()
	assert.Contains(t, output, "Custom", "Expected Custom Behavior from Error Handler")
}

func TestShellCompletionForIncompleteFlags(t *testing.T) {
	cmd := &Command{
		Flags: []Flag{
			&Int64Flag{
				Name: "test-completion",
			},
		},
		EnableShellCompletion: true,
		ShellComplete: func(_ context.Context, cmd *Command) {
			for _, command := range cmd.Commands {
				if command.Hidden {
					continue
				}

				for _, name := range command.Names() {
					_, _ = fmt.Fprintln(cmd.Writer, name)
				}
			}

			for _, fl := range cmd.Flags {
				for _, name := range fl.Names() {
					if name == GenerateShellCompletionFlag.Names()[0] {
						continue
					}

					switch name = strings.TrimSpace(name); len(name) {
					case 0:
					case 1:
						_, _ = fmt.Fprintln(cmd.Writer, "-"+name)
					default:
						_, _ = fmt.Fprintln(cmd.Writer, "--"+name)
					}
				}
			}
		},
		Action: func(context.Context, *Command) error {
			return fmt.Errorf("should not get here")
		},
		Writer: io.Discard,
	}

	err := cmd.Run(buildTestContext(t), []string{"", "--test-completion", completionFlag})
	assert.NoError(t, err, "app should not return an error")
}

func TestWhenExitSubCommandWithCodeThenCommandQuitUnexpectedly(t *testing.T) {
	testCode := 104

	cmd := buildMinimalTestCommand()
	cmd.Commands = []*Command{
		{
			Name: "cmd",
			Commands: []*Command{
				{
					Name: "subcmd",
					Action: func(context.Context, *Command) error {
						return Exit("exit error", testCode)
					},
				},
			},
		},
	}

	// set user function as ExitErrHandler
	exitCodeFromExitErrHandler := int(0)
	cmd.ExitErrHandler = func(_ context.Context, _ *Command, err error) {
		if exitErr, ok := err.(ExitCoder); ok {
			exitCodeFromExitErrHandler = exitErr.ExitCode()
		}
	}

	// keep and restore original OsExiter
	origExiter := OsExiter
	t.Cleanup(func() { OsExiter = origExiter })

	// set user function as OsExiter
	exitCodeFromOsExiter := int(0)
	OsExiter = func(exitCode int) {
		exitCodeFromOsExiter = exitCode
	}

	r := require.New(t)

	r.Error(cmd.Run(buildTestContext(t), []string{
		"myapp",
		"cmd",
		"subcmd",
	}))

	r.Equal(0, exitCodeFromOsExiter)
	r.Equal(testCode, exitCodeFromExitErrHandler)
}

func buildMinimalTestCommand() *Command {
	// reset the help flag because tests may have set it
	HelpFlag.(*BoolFlag).hasBeenSet = false
	return &Command{Writer: io.Discard}
}

func TestSetupInitializesBothWriters(t *testing.T) {
	cmd := &Command{}

	cmd.setupDefaults([]string{"test"})

	assert.Equal(t, cmd.ErrWriter, os.Stderr, "expected a.ErrWriter to be os.Stderr")
	assert.Equal(t, cmd.Writer, os.Stdout, "expected a.Writer to be os.Stdout")
}

func TestSetupInitializesOnlyNilWriters(t *testing.T) {
	wr := &bytes.Buffer{}
	cmd := &Command{
		ErrWriter: wr,
	}

	cmd.setupDefaults([]string{"test"})

	assert.Equal(t, cmd.ErrWriter, wr, "expected a.ErrWriter to be a *bytes.Buffer instance")
	assert.Equal(t, cmd.Writer, os.Stdout, "expected a.Writer to be os.Stdout")
}

func TestFlagAction(t *testing.T) {
	now := time.Now().UTC().Truncate(time.Minute)
	testCases := []struct {
		name string
		args []string
		err  string
		exp  string
	}{
		{
			name: "flag_string",
			args: []string{"app", "--f_string=string"},
			exp:  "string ",
		},
		{
			name: "flag_string_error",
			args: []string{"app", "--f_string="},
			err:  "flag needs an argument: --f_string=",
		},
		{
			name: "flag_string_error2",
			args: []string{"app", "--f_string=", "--f_bool"},
			err:  "flag needs an argument: --f_string=",
		},
		{
			name: "flag_string_slice",
			args: []string{"app", "--f_string_slice=s1,s2,s3"},
			exp:  "[s1 s2 s3] ",
		},
		{
			name: "flag_string_slice_error",
			args: []string{"app", "--f_string_slice=err"},
			err:  "error string slice",
		},
		{
			name: "flag_bool",
			args: []string{"app", "--f_bool"},
			exp:  "true ",
		},
		{
			name: "flag_bool_error",
			args: []string{"app", "--f_bool=false"},
			err:  "value is false",
		},
		{
			name: "flag_duration",
			args: []string{"app", "--f_duration=1h30m20s"},
			exp:  "1h30m20s ",
		},
		{
			name: "flag_duration_error",
			args: []string{"app", "--f_duration=0"},
			err:  "empty duration",
		},
		{
			name: "flag_float64",
			args: []string{"app", "--f_float64=3.14159"},
			exp:  "3.14159 ",
		},
		{
			name: "flag_float64_error",
			args: []string{"app", "--f_float64=-1"},
			err:  "negative float64",
		},
		{
			name: "flag_float64_slice",
			args: []string{"app", "--f_float64_slice=1.1,2.2,3.3"},
			exp:  "[1.1 2.2 3.3] ",
		},
		{
			name: "flag_float64_slice_error",
			args: []string{"app", "--f_float64_slice=-1"},
			err:  "invalid float64 slice",
		},
		{
			name: "flag_int",
			args: []string{"app", "--f_int=1"},
			exp:  "1 ",
		},
		{
			name: "flag_int_error",
			args: []string{"app", "--f_int=-1"},
			err:  "negative int",
		},
		{
			name: "flag_int_slice",
			args: []string{"app", "--f_int_slice=1,2,3"},
			exp:  "[1 2 3] ",
		},
		{
			name: "flag_int_slice_error",
			args: []string{"app", "--f_int_slice=-1"},
			err:  "invalid int slice",
		},
		{
			name: "flag_timestamp",
			args: []string{"app", "--f_timestamp", now.Format(time.DateTime)},
			exp:  now.UTC().Format(time.RFC3339) + " ",
		},
		{
			name: "flag_timestamp_error",
			args: []string{"app", "--f_timestamp", "0001-01-01 00:00:00"},
			err:  "zero timestamp",
		},
		{
			name: "flag_uint",
			args: []string{"app", "--f_uint=1"},
			exp:  "1 ",
		},
		{
			name: "flag_uint_error",
			args: []string{"app", "--f_uint=0"},
			err:  "zero uint64",
		},
		{
			name: "flag_no_action",
			args: []string{"app", "--f_no_action=xx"},
			exp:  "",
		},
		{
			name: "command_flag",
			args: []string{"app", "c1", "--f_string=c1"},
			exp:  "c1 ",
		},
		{
			name: "subCommand_flag",
			args: []string{"app", "c1", "sub1", "--f_string=sub1"},
			exp:  "sub1 ",
		},
		// TBD
		/*		{
				name: "mixture",
				args: []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"},
				exp:  "app 1 [1 2 3] 1h30m20s c1 sub1 ",
			},*/
		{
			name: "flag_string_map",
			args: []string{"app", "--f_string_map=s1=s2,s3="},
			exp:  "map[s1:s2 s3:]",
		},
		{
			name: "flag_string_map_error",
			args: []string{"app", "--f_string_map=err="},
			err:  "error string map",
		},
	}

	for _, test := range testCases {
		t.Run(test.name, func(t *testing.T) {
			out := &bytes.Buffer{}

			newStringFlag := func(local bool) *StringFlag {
				return &StringFlag{
					Local: local,
					Name:  "f_string",
					Action: func(_ context.Context, cmd *Command, v string) error {
						if v == "" {
							return fmt.Errorf("empty string")
						}
						_, err := cmd.Root().Writer.Write([]byte(v + " "))
						return err
					},
				}
			}

			cmd := &Command{
				Writer: out,
				Name:   "app",
				Commands: []*Command{
					{
						Name:   "c1",
						Flags:  []Flag{newStringFlag(true)},
						Action: func(_ context.Context, cmd *Command) error { return nil },
						Commands: []*Command{
							{
								Name:   "sub1",
								Action: func(context.Context, *Command) error { return nil },
								Flags:  []Flag{newStringFlag(true)},
							},
						},
					},
				},
				Flags: []Flag{
					newStringFlag(true),
					&StringFlag{
						Name: "f_no_action",
					},
					&StringSliceFlag{
						Local: true,
						Name:  "f_string_slice",
						Action: func(_ context.Context, cmd *Command, v []string) error {
							if v[0] == "err" {
								return fmt.Errorf("error string slice")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%v ", v)
							return err
						},
					},
					&BoolFlag{
						Name:  "f_bool",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v bool) error {
							if !v {
								return fmt.Errorf("value is false")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%t ", v)
							return err
						},
					},
					&DurationFlag{
						Name:  "f_duration",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v time.Duration) error {
							if v == 0 {
								return fmt.Errorf("empty duration")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, v.String()+" ")
							return err
						},
					},
					&FloatFlag{
						Name:  "f_float64",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v float64) error {
							if v < 0 {
								return fmt.Errorf("negative float64")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, strconv.FormatFloat(v, 'f', -1, 64)+" ")
							return err
						},
					},
					&FloatSliceFlag{
						Name:  "f_float64_slice",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v []float64) error {
							if len(v) > 0 && v[0] < 0 {
								return fmt.Errorf("invalid float64 slice")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%v ", v)
							return err
						},
					},
					&Int64Flag{
						Name:  "f_int",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v int64) error {
							if v < 0 {
								return fmt.Errorf("negative int")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%v ", v)
							return err
						},
					},
					&Int64SliceFlag{
						Name:  "f_int_slice",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v []int64) error {
							if len(v) > 0 && v[0] < 0 {
								return fmt.Errorf("invalid int slice")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%v ", v)
							return err
						},
					},
					&TimestampFlag{
						Name:  "f_timestamp",
						Local: true,
						Config: TimestampConfig{
							Timezone: time.UTC,
							Layouts:  []string{time.DateTime},
						},
						Action: func(_ context.Context, cmd *Command, v time.Time) error {
							if v.IsZero() {
								return fmt.Errorf("zero timestamp")
							}

							_, err := cmd.Root().Writer.Write([]byte(v.Format(time.RFC3339) + " "))
							return err
						},
					},
					&Uint64Flag{
						Name:  "f_uint",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v uint64) error {
							if v == 0 {
								return fmt.Errorf("zero uint64")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%v ", v)
							return err
						},
					},
					&StringMapFlag{
						Name:  "f_string_map",
						Local: true,
						Action: func(_ context.Context, cmd *Command, v map[string]string) error {
							if _, ok := v["err"]; ok {
								return fmt.Errorf("error string map")
							}
							_, err := fmt.Fprintf(cmd.Root().Writer, "%v", v)
							return err
						},
					},
				},
				Action: func(context.Context, *Command) error { return nil },
			}

			err := cmd.Run(buildTestContext(t), test.args)

			r := require.New(t)

			if test.err != "" {
				r.EqualError(err, test.err)
				return
			}

			r.NoError(err)
			r.Equal(test.exp, out.String())
		})
	}
}

func TestLocalFlagError(t *testing.T) {
	var topInt int64

	cmd := &Command{
		Flags: []Flag{
			&Int64Flag{
				Name:        "cmdFlag",
				Destination: &topInt,
				Local:       true,
			},
		},
		Commands: []*Command{
			{
				Name: "subcmd",
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{
		"app",
		"subcmd",
		"--cmdFlag", "11",
	})

	assert.Error(t, err)
	assert.Contains(t, err.Error(), "flag provided but not defined: -cmdFlag")
}

func TestPersistentFlag(t *testing.T) {
	var topInt, topPersistentInt, subCommandInt, appOverrideInt int64
	var appFlag string
	var appRequiredFlag string
	var appOverrideCmdInt int64
	var appSliceFloat64 []float64
	var persistentCommandSliceInt []int64
	var persistentFlagActionCount int64

	cmd := &Command{
		Flags: []Flag{
			&StringFlag{
				Name:        "persistentCommandFlag",
				Destination: &appFlag,
				Action: func(context.Context, *Command, string) error {
					persistentFlagActionCount++
					return nil
				},
			},
			&Int64SliceFlag{
				Name:        "persistentCommandSliceFlag",
				Destination: &persistentCommandSliceInt,
			},
			&FloatSliceFlag{
				Name:  "persistentCommandFloatSliceFlag",
				Value: []float64{11.3, 12.5},
			},
			&Int64Flag{
				Name:        "persistentCommandOverrideFlag",
				Destination: &appOverrideInt,
			},
			&StringFlag{
				Name:        "persistentRequiredCommandFlag",
				Required:    true,
				Destination: &appRequiredFlag,
			},
		},
		Commands: []*Command{
			{
				Name: "cmd",
				Flags: []Flag{
					&Int64Flag{
						Name:        "cmdFlag",
						Destination: &topInt,
						Local:       true,
					},
					&Int64Flag{
						Name:        "cmdPersistentFlag",
						Destination: &topPersistentInt,
					},
					&Int64Flag{
						Name:        "paof",
						Aliases:     []string{"persistentCommandOverrideFlag"},
						Destination: &appOverrideCmdInt,
						Local:       true,
					},
				},
				Commands: []*Command{
					{
						Name: "subcmd",
						Flags: []Flag{
							&Int64Flag{
								Name:        "cmdFlag",
								Destination: &subCommandInt,
								Local:       true,
							},
						},
						Action: func(_ context.Context, cmd *Command) error {
							appSliceFloat64 = cmd.FloatSlice("persistentCommandFloatSliceFlag")
							return nil
						},
					},
				},
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{
		"app",
		"--persistentCommandFlag", "hello",
		"--persistentCommandSliceFlag", "100",
		"--persistentCommandOverrideFlag", "102",
		"cmd",
		"--cmdFlag", "12",
		"--persistentCommandSliceFlag", "102",
		"--persistentCommandFloatSliceFlag", "102.455",
		"--paof", "105",
		"--persistentRequiredCommandFlag", "hellor",
		"subcmd",
		"--cmdPersistentFlag", "20",
		"--cmdFlag", "11",
		"--persistentCommandFlag", "bar",
		"--persistentCommandSliceFlag", "130",
		"--persistentCommandFloatSliceFlag", "3.1445",
	})

	require.NoError(t, err)

	assert.Equal(t, "bar", appFlag)
	assert.Equal(t, "hellor", appRequiredFlag)
	assert.Equal(t, int64(12), topInt)
	assert.Equal(t, int64(20), topPersistentInt)

	// this should be changed from app since
	// cmd overrides it
	assert.Equal(t, int64(102), appOverrideInt)
	assert.Equal(t, int64(11), subCommandInt)
	assert.Equal(t, int64(105), appOverrideCmdInt)
	assert.Equal(t, []int64{100, 102, 130}, persistentCommandSliceInt)
	assert.Equal(t, []float64{102.455, 3.1445}, appSliceFloat64)
	assert.Equal(t, int64(2), persistentFlagActionCount, "Expected persistent flag action to be called 2 times")
}

func TestPersistentFlagIsSet(t *testing.T) {
	result := ""
	resultIsSet := false

	app := &Command{
		Name: "root",
		Flags: []Flag{
			&StringFlag{
				Name: "result",
			},
		},
		Commands: []*Command{
			{
				Name: "sub",
				Action: func(_ context.Context, cmd *Command) error {
					result = cmd.String("result")
					resultIsSet = cmd.IsSet("result")
					return nil
				},
			},
		},
	}

	err := app.Run(context.Background(), []string{"root", "--result", "before", "sub"})
	require.NoError(t, err)
	require.Equal(t, "before", result)
	require.True(t, resultIsSet)

	err = app.Run(context.Background(), []string{"root", "sub", "--result", "after"})
	require.NoError(t, err)
	require.Equal(t, "after", result)
	require.True(t, resultIsSet)
}

func TestRequiredFlagDelayed(t *testing.T) {
	sf := &StringFlag{
		Name:     "result",
		Required: true,
	}

	expectedErr := &errRequiredFlags{
		missingFlags: []string{sf.Name},
	}

	tests := []struct {
		name        string
		args        []string
		errExpected error
	}{
		{
			name:        "leaf help",
			args:        []string{"root", "sub", "-h"},
			errExpected: nil,
		},
		{
			name:        "leaf action",
			args:        []string{"root", "sub"},
			errExpected: expectedErr,
		},
		{
			name:        "leaf flags set",
			args:        []string{"root", "sub", "--if", "10"},
			errExpected: expectedErr,
		},
		{
			name:        "leaf invalid flags set",
			args:        []string{"root", "sub", "--xx"},
			errExpected: expectedErr,
		},
	}

	app := &Command{
		Name: "root",
		Flags: []Flag{
			sf,
		},
		Commands: []*Command{
			{
				Name: "sub",
				Flags: []Flag{
					&Int64Flag{
						Name:     "if",
						Required: true,
					},
				},
				Action: func(ctx context.Context, c *Command) error {
					return nil
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			err := app.Run(context.Background(), test.args)
			if test.errExpected == nil {
				require.NoError(t, err)
			} else {
				require.ErrorAs(t, err, &test.errExpected)
			}
		})
	}
}

func TestRequiredPersistentFlag(t *testing.T) {
	app := &Command{
		Name: "root",
		Flags: []Flag{
			&StringFlag{
				Name:     "result",
				Required: true,
			},
		},
		Commands: []*Command{
			{
				Name: "sub",
				Action: func(ctx context.Context, c *Command) error {
					return nil
				},
			},
		},
	}

	err := app.Run(context.Background(), []string{"root", "sub"})
	require.Error(t, err)

	err = app.Run(context.Background(), []string{"root", "sub", "--result", "after"})
	require.NoError(t, err)
}

func TestFlagDuplicates(t *testing.T) {
	tests := []struct {
		name        string
		args        []string
		errExpected bool
	}{
		{
			name: "all args present once",
			args: []string{"foo", "--sflag", "hello", "--isflag", "1", "--isflag", "2", "--fsflag", "2.0", "--iflag", "10", "--bifflag"},
		},
		{
			name: "duplicate non slice flag(duplicatable)",
			args: []string{"foo", "--sflag", "hello", "--isflag", "1", "--isflag", "2", "--fsflag", "2.0", "--iflag", "10", "--iflag", "20"},
		},
		{
			name:        "duplicate non slice flag(non duplicatable)",
			args:        []string{"foo", "--sflag", "hello", "--isflag", "1", "--isflag", "2", "--fsflag", "2.0", "--iflag", "10", "--sflag", "trip"},
			errExpected: true,
		},
		{
			name:        "duplicate slice flag(non duplicatable)",
			args:        []string{"foo", "--sflag", "hello", "--isflag", "1", "--isflag", "2", "--fsflag", "2.0", "--fsflag", "3.0", "--iflag", "10"},
			errExpected: true,
		},
		{
			name:        "duplicate bool inverse flag(non duplicatable)",
			args:        []string{"foo", "--bifflag", "--bifflag"},
			errExpected: true,
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			cmd := &Command{
				Flags: []Flag{
					&StringFlag{
						Name:     "sflag",
						OnlyOnce: true,
					},
					&Int64SliceFlag{
						Name: "isflag",
					},
					&FloatSliceFlag{
						Name:     "fsflag",
						OnlyOnce: true,
					},
					&BoolWithInverseFlag{
						Name:     "bifflag",
						OnlyOnce: true,
					},
					&Int64Flag{
						Name: "iflag",
					},
				},
				Action: func(context.Context, *Command) error {
					return nil
				},
			}

			err := cmd.Run(buildTestContext(t), test.args)
			if test.errExpected {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestShorthandCommand(t *testing.T) {
	af := func(p *int) ActionFunc {
		return func(context.Context, *Command) error {
			*p = *p + 1
			return nil
		}
	}

	var cmd1, cmd2 int

	cmd := &Command{
		PrefixMatchCommands: true,
		Commands: []*Command{
			{
				Name:    "cthdisd",
				Aliases: []string{"cth"},
				Action:  af(&cmd1),
			},
			{
				Name:    "cthertoop",
				Aliases: []string{"cer"},
				Action:  af(&cmd2),
			},
		},
	}

	err := cmd.Run(buildTestContext(t), []string{"foo", "cth"})
	assert.NoError(t, err)
	assert.True(t, cmd1 == 1 && cmd2 == 0, "Expected command1 to be triggered once")

	cmd1 = 0
	cmd2 = 0

	err = cmd.Run(buildTestContext(t), []string{"foo", "cthd"})
	assert.NoError(t, err)
	assert.True(t, cmd1 == 1 && cmd2 == 0, "Expected command1 to be triggered once")

	cmd1 = 0
	cmd2 = 0

	err = cmd.Run(buildTestContext(t), []string{"foo", "cthe"})
	assert.NoError(t, err)
	assert.True(t, cmd1 == 1 && cmd2 == 0, "Expected command1 to be triggered once")

	cmd1 = 0
	cmd2 = 0

	err = cmd.Run(buildTestContext(t), []string{"foo", "cthert"})
	assert.NoError(t, err)
	assert.True(t, cmd1 == 0 && cmd2 == 1, "Expected command1 to be triggered once")

	cmd1 = 0
	cmd2 = 0

	err = cmd.Run(buildTestContext(t), []string{"foo", "cthet"})
	assert.NoError(t, err)
	assert.True(t, cmd1 == 0 && cmd2 == 1, "Expected command1 to be triggered once")
}

func TestCommand_Int(t *testing.T) {
	pCmd := &Command{
		Flags: []Flag{
			&Int64Flag{
				Name:  "myflag",
				Value: 12,
			},
		},
	}
	cmd := &Command{
		Flags: []Flag{
			&Int64Flag{
				Name:  "top-flag",
				Value: 13,
			},
		},
		parent: pCmd,
	}

	require.Equal(t, int64(12), cmd.Int64("myflag"))
	require.Equal(t, int64(13), cmd.Int64("top-flag"))
}

func TestCommand_Uint(t *testing.T) {
	pCmd := &Command{
		Flags: []Flag{
			&Uint64Flag{
				Name:  "myflagUint",
				Value: 13,
			},
		},
	}
	cmd := &Command{
		Flags: []Flag{
			&Uint64Flag{
				Name:  "top-flag",
				Value: 14,
			},
		},
		parent: pCmd,
	}

	require.Equal(t, uint64(13), cmd.Uint64("myflagUint"))
	require.Equal(t, uint64(14), cmd.Uint64("top-flag"))
}

func TestCommand_Float64(t *testing.T) {
	pCmd := &Command{
		Flags: []Flag{
			&FloatFlag{
				Name:  "myflag",
				Value: 17,
			},
		},
	}
	cmd := &Command{
		Flags: []Flag{
			&FloatFlag{
				Name:  "top-flag",
				Value: 18,
			},
		},
		parent: pCmd,
	}

	r := require.New(t)
	r.Equal(float64(17), cmd.Float("myflag"))
	r.Equal(float64(18), cmd.Float("top-flag"))
}

func TestCommand_Duration(t *testing.T) {
	pCmd := &Command{
		Flags: []Flag{
			&DurationFlag{
				Name:  "myflag",
				Value: 12 * time.Second,
			},
		},
	}
	cmd := &Command{
		Flags: []Flag{
			&DurationFlag{
				Name:  "top-flag",
				Value: 13 * time.Second,
			},
		},
		parent: pCmd,
	}

	r := require.New(t)
	r.Equal(12*time.Second, cmd.Duration("myflag"))
	r.Equal(13*time.Second, cmd.Duration("top-flag"))
}

func TestCommand_Timestamp(t *testing.T) {
	t1 := time.Time{}.Add(12 * time.Second)
	t2 := time.Time{}.Add(13 * time.Second)

	cmd := &Command{
		Name: "hello",
		Flags: []Flag{
			&TimestampFlag{
				Name:  "myflag",
				Value: t1,
			},
		},
		Action: func(ctx context.Context, c *Command) error {
			return nil
		},
	}

	pCmd := &Command{
		Flags: []Flag{
			&TimestampFlag{
				Name:  "top-flag",
				Value: t2,
			},
		},
		Commands: []*Command{
			cmd,
		},
	}

	err := pCmd.Run(context.Background(), []string{"foo", "hello"})
	assert.NoError(t, err)

	r := require.New(t)
	r.Equal(t1, cmd.Timestamp("myflag"))
	r.Equal(t2, cmd.Timestamp("top-flag"))
}

func TestCommand_String(t *testing.T) {
	pCmd := &Command{
		Flags: []Flag{
			&StringFlag{
				Name:  "myflag",
				Value: "hello world",
			},
		},
	}
	cmd := &Command{
		Flags: []Flag{
			&StringFlag{
				Name:  "top-flag",
				Value: "hai veld",
			},
		},
		parent: pCmd,
	}

	r := require.New(t)
	r.Equal("hello world", cmd.String("myflag"))
	r.Equal("hai veld", cmd.String("to
Download .txt
gitextract_oit1zf28/

├── .github/
│   ├── CODEOWNERS
│   ├── ISSUE_TEMPLATE/
│   │   ├── question.md
│   │   ├── v1-bug-report.md
│   │   ├── v2-bug-report.md
│   │   ├── v3-bug-report.md
│   │   └── v3-feature-request.md
│   ├── codecov.yml
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── lint.yml
│       ├── publish-docs.yml
│       └── test.yml
├── .gitignore
├── .golangci.yaml
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Makefile
├── README.md
├── args.go
├── args_test.go
├── autocomplete/
│   ├── bash_autocomplete
│   ├── fish_autocomplete
│   ├── powershell_autocomplete.ps1
│   └── zsh_autocomplete
├── category.go
├── cli.go
├── cli_test.go
├── command.go
├── command_parse.go
├── command_run.go
├── command_setup.go
├── command_stop_on_nth_arg_test.go
├── command_test.go
├── completion.go
├── completion_test.go
├── docs/
│   ├── CHANGELOG.md
│   ├── CNAME
│   ├── CONTRIBUTING.md
│   ├── RELEASING.md
│   ├── SECURITY.md
│   ├── go.mod
│   ├── go.sum
│   ├── index.md
│   ├── migrate-v1-to-v2.md
│   ├── migrate-v2-to-v3.md
│   ├── package.go
│   ├── v1/
│   │   ├── examples/
│   │   │   ├── arguments.md
│   │   │   ├── bash-completions.md
│   │   │   ├── combining-short-options.md
│   │   │   ├── exit-codes.md
│   │   │   ├── flags.md
│   │   │   ├── generated-help-text.md
│   │   │   ├── greet.md
│   │   │   ├── subcommands-categories.md
│   │   │   ├── subcommands.md
│   │   │   └── version-flag.md
│   │   ├── getting-started.md
│   │   └── migrating-to-v2.md
│   ├── v2/
│   │   ├── examples/
│   │   │   ├── arguments.md
│   │   │   ├── bash-completions.md
│   │   │   ├── combining-short-options.md
│   │   │   ├── exit-codes.md
│   │   │   ├── flags.md
│   │   │   ├── full-api-example.md
│   │   │   ├── generated-help-text.md
│   │   │   ├── greet.md
│   │   │   ├── subcommands-categories.md
│   │   │   ├── subcommands.md
│   │   │   ├── suggestions.md
│   │   │   ├── timestamp-flag.md
│   │   │   └── version-flag.md
│   │   ├── getting-started.md
│   │   ├── migrating-from-older-releases.md
│   │   └── migrating-to-v3.md
│   └── v3/
│       ├── examples/
│       │   ├── arguments/
│       │   │   ├── advanced.md
│       │   │   └── basics.md
│       │   ├── completions/
│       │   │   ├── customizations.md
│       │   │   └── shell-completions.md
│       │   ├── exit-codes.md
│       │   ├── flags/
│       │   │   ├── advanced.md
│       │   │   ├── basics.md
│       │   │   ├── short-options.md
│       │   │   └── value-sources.md
│       │   ├── full-api-example.md
│       │   ├── greet.md
│       │   ├── help/
│       │   │   ├── generated-help-text.md
│       │   │   └── suggestions.md
│       │   └── subcommands/
│       │       ├── basics.md
│       │       └── categories.md
│       ├── getting-started.md
│       ├── index.md
│       └── migrating-from-older-releases.md
├── docs.go
├── errors.go
├── errors_test.go
├── examples/
│   ├── example-cli/
│   │   └── example-cli.go
│   └── example-hello-world/
│       └── example-hello-world.go
├── examples_test.go
├── fish.go
├── fish_test.go
├── flag.go
├── flag_bool.go
├── flag_bool_with_inverse.go
├── flag_bool_with_inverse_test.go
├── flag_duration.go
├── flag_ext.go
├── flag_float.go
├── flag_float_slice.go
├── flag_float_slice_test.go
├── flag_float_test.go
├── flag_generic.go
├── flag_impl.go
├── flag_int.go
├── flag_int_slice.go
├── flag_int_slice_test.go
├── flag_int_test.go
├── flag_map_impl.go
├── flag_mutex.go
├── flag_mutex_test.go
├── flag_number_slice.go
├── flag_number_slice_test.go
├── flag_slice_base.go
├── flag_string.go
├── flag_string_map.go
├── flag_string_slice.go
├── flag_test.go
├── flag_timestamp.go
├── flag_uint.go
├── flag_uint_slice.go
├── flag_uint_slice_test.go
├── flag_uint_test.go
├── flag_validation_test.go
├── funcs.go
├── go.mod
├── go.sum
├── godoc-current.txt
├── help.go
├── help_test.go
├── helpers_test.go
├── mkdocs-requirements.txt
├── mkdocs.yml
├── scripts/
│   └── build.go
├── sort.go
├── sort_test.go
├── staticcheck.conf
├── suggestions.go
├── suggestions_test.go
├── template.go
├── testdata/
│   ├── empty.yml
│   ├── expected-doc-full.man
│   ├── expected-doc-full.md
│   ├── expected-doc-no-authors.md
│   ├── expected-doc-no-commands.md
│   ├── expected-doc-no-flags.md
│   ├── expected-doc-no-usagetext.md
│   ├── expected-fish-full.fish
│   ├── expected-tabular-markdown-custom-app-path.md
│   ├── expected-tabular-markdown-full.md
│   └── godoc-v3.x.txt
├── value_source.go
└── value_source_test.go
Download .txt
SYMBOL INDEX (1011 symbols across 64 files)

FILE: args.go
  type Args (line 8) | type Args interface
  type stringSliceArgs (line 24) | type stringSliceArgs struct
    method Get (line 28) | func (a *stringSliceArgs) Get(n int) string {
    method First (line 35) | func (a *stringSliceArgs) First() string {
    method Tail (line 39) | func (a *stringSliceArgs) Tail() []string {
    method Len (line 50) | func (a *stringSliceArgs) Len() int {
    method Present (line 54) | func (a *stringSliceArgs) Present() bool {
    method Slice (line 58) | func (a *stringSliceArgs) Slice() []string {
  type Argument (line 66) | type Argument interface
  type ArgumentBase (line 87) | type ArgumentBase struct
  method HasName (line 97) | func (a *ArgumentBase[T, C, VC]) HasName(s string) bool {
  method Usage (line 101) | func (a *ArgumentBase[T, C, VC]) Usage() string {
  method Parse (line 110) | func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
  method Get (line 138) | func (a *ArgumentBase[T, C, VC]) Get() any {
  type ArgumentsBase (line 146) | type ArgumentsBase struct
  method HasName (line 158) | func (a *ArgumentsBase[T, C, VC]) HasName(s string) bool {
  method Usage (line 162) | func (a *ArgumentsBase[T, C, VC]) Usage() string {
  method Parse (line 180) | func (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error) {
  method Get (line 219) | func (a *ArgumentsBase[T, C, VC]) Get() any {
  method getArgValue (line 261) | func (c *Command) getArgValue(name string) any {
  function arg (line 273) | func arg[T any](name string, c *Command) T {
  method StringArg (line 282) | func (c *Command) StringArg(name string) string {
  method StringArgs (line 286) | func (c *Command) StringArgs(name string) []string {
  method FloatArg (line 290) | func (c *Command) FloatArg(name string) float64 {
  method FloatArgs (line 294) | func (c *Command) FloatArgs(name string) []float64 {
  method Float32Arg (line 298) | func (c *Command) Float32Arg(name string) float32 {
  method Float32Args (line 302) | func (c *Command) Float32Args(name string) []float32 {
  method Float64Arg (line 306) | func (c *Command) Float64Arg(name string) float64 {
  method Float64Args (line 310) | func (c *Command) Float64Args(name string) []float64 {
  method IntArg (line 314) | func (c *Command) IntArg(name string) int {
  method IntArgs (line 318) | func (c *Command) IntArgs(name string) []int {
  method Int8Arg (line 322) | func (c *Command) Int8Arg(name string) int8 {
  method Int8Args (line 326) | func (c *Command) Int8Args(name string) []int8 {
  method Int16Arg (line 330) | func (c *Command) Int16Arg(name string) int16 {
  method Int16Args (line 334) | func (c *Command) Int16Args(name string) []int16 {
  method Int32Arg (line 338) | func (c *Command) Int32Arg(name string) int32 {
  method Int32Args (line 342) | func (c *Command) Int32Args(name string) []int32 {
  method Int64Arg (line 346) | func (c *Command) Int64Arg(name string) int64 {
  method Int64Args (line 350) | func (c *Command) Int64Args(name string) []int64 {
  method UintArg (line 354) | func (c *Command) UintArg(name string) uint {
  method Uint8Arg (line 358) | func (c *Command) Uint8Arg(name string) uint8 {
  method Uint16Arg (line 362) | func (c *Command) Uint16Arg(name string) uint16 {
  method Uint32Arg (line 366) | func (c *Command) Uint32Arg(name string) uint32 {
  method Uint64Arg (line 370) | func (c *Command) Uint64Arg(name string) uint64 {
  method UintArgs (line 374) | func (c *Command) UintArgs(name string) []uint {
  method Uint8Args (line 378) | func (c *Command) Uint8Args(name string) []uint8 {
  method Uint16Args (line 382) | func (c *Command) Uint16Args(name string) []uint16 {
  method Uint32Args (line 386) | func (c *Command) Uint32Args(name string) []uint32 {
  method Uint64Args (line 390) | func (c *Command) Uint64Args(name string) []uint64 {
  method TimestampArg (line 394) | func (c *Command) TimestampArg(name string) time.Time {
  method TimestampArgs (line 398) | func (c *Command) TimestampArgs(name string) []time.Time {

FILE: args_test.go
  function TestArgNotSet (line 11) | func TestArgNotSet(t *testing.T) {
  function TestArgsMaxNotSet (line 20) | func TestArgsMaxNotSet(t *testing.T) {
  function TestArgsMinGtMax (line 33) | func TestArgsMinGtMax(t *testing.T) {
  function TestArgsFloatTypes (line 48) | func TestArgsFloatTypes(t *testing.T) {
  function TestArgsIntTypes (line 75) | func TestArgsIntTypes(t *testing.T) {
  function TestArgsFloatSliceTypes (line 101) | func TestArgsFloatSliceTypes(t *testing.T) {
  function TestArgsIntSliceTypes (line 124) | func TestArgsIntSliceTypes(t *testing.T) {
  function TestArgsUintTypes (line 149) | func TestArgsUintTypes(t *testing.T) {
  function TestArgsUintSliceTypes (line 173) | func TestArgsUintSliceTypes(t *testing.T) {
  function TestArgumentsRootCommand (line 198) | func TestArgumentsRootCommand(t *testing.T) {
  function TestArgumentsInvalidType (line 299) | func TestArgumentsInvalidType(t *testing.T) {
  function TestArgumentsSubcommand (line 324) | func TestArgumentsSubcommand(t *testing.T) {
  function TestArgUsage (line 418) | func TestArgUsage(t *testing.T) {
  function TestArgsUsage (line 445) | func TestArgsUsage(t *testing.T) {
  function TestSingleOptionalArg (line 510) | func TestSingleOptionalArg(t *testing.T) {
  function TestUnboundedArgs (line 555) | func TestUnboundedArgs(t *testing.T) {

FILE: category.go
  type CommandCategories (line 6) | type CommandCategories interface
  type commandCategories (line 13) | type commandCategories
    method Less (line 20) | func (c *commandCategories) Less(i, j int) bool {
    method Len (line 24) | func (c *commandCategories) Len() int {
    method Swap (line 28) | func (c *commandCategories) Swap(i, j int) {
    method AddCommand (line 32) | func (c *commandCategories) AddCommand(category string, command *Comma...
    method Categories (line 44) | func (c *commandCategories) Categories() []CommandCategory {
  function newCommandCategories (line 15) | func newCommandCategories() CommandCategories {
  type CommandCategory (line 53) | type CommandCategory interface
  type commandCategory (line 60) | type commandCategory struct
    method Name (line 65) | func (c *commandCategory) Name() string {
    method VisibleCommands (line 69) | func (c *commandCategory) VisibleCommands() []*Command {
  type FlagCategories (line 84) | type FlagCategories interface
  type defaultFlagCategories (line 91) | type defaultFlagCategories struct
    method AddFlag (line 136) | func (f *defaultFlagCategories) AddFlag(category string, fl Flag) {
    method VisibleCategories (line 144) | func (f *defaultFlagCategories) VisibleCategories() []VisibleFlagCateg...
  function newFlagCategories (line 95) | func newFlagCategories() FlagCategories {
  function newFlagCategoriesFromFlags (line 101) | func newFlagCategoriesFromFlags(fs []Flag) FlagCategories {
  type VisibleFlagCategory (line 161) | type VisibleFlagCategory interface
  type defaultVisibleFlagCategory (line 168) | type defaultVisibleFlagCategory struct
    method Name (line 173) | func (fc *defaultVisibleFlagCategory) Name() string {
    method Flags (line 177) | func (fc *defaultVisibleFlagCategory) Flags() []Flag {

FILE: cli.go
  function tracef (line 34) | func tracef(format string, a ...any) {

FILE: cli_test.go
  function expectFileContent (line 14) | func expectFileContent(t *testing.T, file, got string) {
  function buildTestContext (line 24) | func buildTestContext(t *testing.T) context.Context {
  function TestTracing (line 31) | func TestTracing(t *testing.T) {

FILE: command.go
  constant ignoreFlagPrefix (line 13) | ignoreFlagPrefix = "test."
  constant commandContextKey (line 15) | commandContextKey = contextKey("cli.context")
  type contextKey (line 18) | type contextKey
  type Command (line 23) | type Command struct
    method FullName (line 171) | func (cmd *Command) FullName() string {
    method Command (line 181) | func (cmd *Command) Command(name string) *Command {
    method checkHelp (line 191) | func (cmd *Command) checkHelp() bool {
    method allFlags (line 197) | func (cmd *Command) allFlags() []Flag {
    method useShortOptionHandling (line 210) | func (cmd *Command) useShortOptionHandling() bool {
    method suggestFlagFromError (line 220) | func (cmd *Command) suggestFlagFromError(err error, commandName string...
    method Names (line 247) | func (cmd *Command) Names() []string {
    method HasName (line 252) | func (cmd *Command) HasName(name string) bool {
    method VisibleCategories (line 258) | func (cmd *Command) VisibleCategories() []CommandCategory {
    method VisibleCommands (line 274) | func (cmd *Command) VisibleCommands() []*Command {
    method VisibleFlagCategories (line 286) | func (cmd *Command) VisibleFlagCategories() []VisibleFlagCategory {
    method VisibleFlags (line 294) | func (cmd *Command) VisibleFlags() []Flag {
    method appendFlag (line 298) | func (cmd *Command) appendFlag(fl Flag) {
    method VisiblePersistentFlags (line 305) | func (cmd *Command) VisiblePersistentFlags() []Flag {
    method appendCommand (line 317) | func (cmd *Command) appendCommand(aCmd *Command) {
    method handleExitCoder (line 324) | func (cmd *Command) handleExitCoder(ctx context.Context, err error) er...
    method argsWithDefaultCommand (line 338) | func (cmd *Command) argsWithDefaultCommand(oldArgs Args) Args {
    method Root (line 346) | func (cmd *Command) Root() *Command {
    method set (line 354) | func (cmd *Command) set(fName string, f Flag, val string) error {
    method lFlag (line 363) | func (cmd *Command) lFlag(name string) Flag {
    method lookupFlag (line 373) | func (cmd *Command) lookupFlag(name string) Flag {
    method lookupAppliedFlag (line 387) | func (cmd *Command) lookupAppliedFlag(name string) Flag {
    method checkRequiredFlag (line 400) | func (cmd *Command) checkRequiredFlag(f Flag) (bool, string) {
    method checkAllRequiredFlags (line 410) | func (cmd *Command) checkAllRequiredFlags() requiredFlagsErr {
    method checkRequiredFlags (line 419) | func (cmd *Command) checkRequiredFlags() requiredFlagsErr {
    method onInvalidFlag (line 441) | func (cmd *Command) onInvalidFlag(ctx context.Context, name string) {
    method NumFlags (line 452) | func (cmd *Command) NumFlags() int {
    method setMultiValueParsingConfig (line 463) | func (cmd *Command) setMultiValueParsingConfig(f Flag) {
    method Set (line 475) | func (cmd *Command) Set(name, value string) error {
    method IsSet (line 485) | func (cmd *Command) IsSet(name string) bool {
    method LocalFlagNames (line 504) | func (cmd *Command) LocalFlagNames() []string {
    method FlagNames (line 531) | func (cmd *Command) FlagNames() []string {
    method Lineage (line 543) | func (cmd *Command) Lineage() []*Command {
    method Count (line 554) | func (cmd *Command) Count(name string) int {
    method Value (line 562) | func (cmd *Command) Value(name string) interface{} {
    method Args (line 574) | func (cmd *Command) Args() Args {
    method NArg (line 579) | func (cmd *Command) NArg() int {
    method runFlagActions (line 583) | func (cmd *Command) runFlagActions(ctx context.Context) error {

FILE: command_parse.go
  constant providedButNotDefinedErrMsg (line 10) | providedButNotDefinedErrMsg = "flag provided but not defined: -"
  constant argumentNotProvidedErrMsg (line 11) | argumentNotProvidedErrMsg   = "flag needs an argument: "
  function flagFromError (line 16) | func flagFromError(err error) (string, error) {
  method parseFlags (line 25) | func (cmd *Command) parseFlags(args Args) (Args, error) {

FILE: command_run.go
  method parseArgsFromStdin (line 12) | func (cmd *Command) parseArgsFromStdin() ([]string, error) {
  method Run (line 92) | func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr ...
  method run (line 97) | func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context...

FILE: command_setup.go
  method setupDefaults (line 11) | func (cmd *Command) setupDefaults(osArgs []string) {
  method setupCommandGraph (line 147) | func (cmd *Command) setupCommandGraph() {
  method setupSubcommand (line 157) | func (cmd *Command) setupSubcommand() {
  method hideHelp (line 181) | func (cmd *Command) hideHelp() bool {
  method ensureHelp (line 192) | func (cmd *Command) ensureHelp() {

FILE: command_stop_on_nth_arg_test.go
  function TestCommand_StopOnNthArg (line 11) | func TestCommand_StopOnNthArg(t *testing.T) {
  function TestCommand_StopOnNthArg_WithSubcommands (line 122) | func TestCommand_StopOnNthArg_WithSubcommands(t *testing.T) {
  function TestCommand_StopOnNthArg_EdgeCases (line 236) | func TestCommand_StopOnNthArg_EdgeCases(t *testing.T) {
  function intPtr (line 299) | func intPtr(i int) *int {

FILE: command_test.go
  function init (line 31) | func init() {
  type opCounts (line 36) | type opCounts struct
  function buildExtendedTestCommand (line 40) | func buildExtendedTestCommand() *Command {
  function TestCommandFlagParsing (line 159) | func TestCommandFlagParsing(t *testing.T) {
  function TestParseAndRunShortOpts (line 202) | func TestParseAndRunShortOpts(t *testing.T) {
  function TestCommand_Run_DoesNotOverwriteErrorFromBefore (line 273) | func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
  function TestCommand_Run_BeforeSavesMetadata (line 291) | func TestCommand_Run_BeforeSavesMetadata(t *testing.T) {
  function TestCommand_Run_BeforeReturnNewContext (line 325) | func TestCommand_Run_BeforeReturnNewContext(t *testing.T) {
  type ctxKey (line 359) | type ctxKey
  type ctxCollector (line 362) | type ctxCollector struct
    method collect (line 370) | func (cc *ctxCollector) collect(ctx context.Context, fnName string) {
  function TestCommand_Run_BeforeReturnNewContextSubcommand (line 386) | func TestCommand_Run_BeforeReturnNewContextSubcommand(t *testing.T) {
  function TestCommand_Run_FlagActionContext (line 436) | func TestCommand_Run_FlagActionContext(t *testing.T) {
  function TestCommand_OnUsageError_hasCommandContext (line 491) | func TestCommand_OnUsageError_hasCommandContext(t *testing.T) {
  function TestCommand_OnUsageError_WithWrongFlagValue (line 506) | func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
  function TestCommand_OnUsageError_WithSubcommand (line 522) | func TestCommand_OnUsageError_WithSubcommand(t *testing.T) {
  function TestCommand_Run_SubcommandsCanUseErrWriter (line 543) | func TestCommand_Run_SubcommandsCanUseErrWriter(t *testing.T) {
  function TestCommandSkipFlagParsing (line 564) | func TestCommandSkipFlagParsing(t *testing.T) {
  function TestCommand_Run_CustomShellCompleteAcceptsMalformedFlags (line 597) | func TestCommand_Run_CustomShellCompleteAcceptsMalformedFlags(t *testing...
  function TestCommand_CanAddVFlagOnSubCommands (line 640) | func TestCommand_CanAddVFlagOnSubCommands(t *testing.T) {
  function TestCommand_VisibleSubcCommands (line 660) | func TestCommand_VisibleSubcCommands(t *testing.T) {
  function TestCommand_VisibleFlagCategories (line 686) | func TestCommand_VisibleFlagCategories(t *testing.T) {
  function TestCommand_RunSubcommandWithDefault (line 738) | func TestCommand_RunSubcommandWithDefault(t *testing.T) {
  function TestCommand_Run (line 768) | func TestCommand_Run(t *testing.T) {
  function TestCommand_Command (line 797) | func TestCommand_Command(t *testing.T) {
  function TestCommand_RunDefaultCommand (line 834) | func TestCommand_RunDefaultCommand(t *testing.T) {
  function TestCommand_RunDefaultCommandWithSubCommand (line 925) | func TestCommand_RunDefaultCommandWithSubCommand(t *testing.T) {
  function TestCommand_RunDefaultCommandWithFlags (line 991) | func TestCommand_RunDefaultCommandWithFlags(t *testing.T) {
  function TestCommand_FlagsFromExtPackage (line 1045) | func TestCommand_FlagsFromExtPackage(t *testing.T) {
  function TestCommand_Setup_defaultsReader (line 1099) | func TestCommand_Setup_defaultsReader(t *testing.T) {
  function TestCommand_Setup_defaultsWriter (line 1105) | func TestCommand_Setup_defaultsWriter(t *testing.T) {
  function TestCommand_CommandWithFlagBeforeTerminator (line 1111) | func TestCommand_CommandWithFlagBeforeTerminator(t *testing.T) {
  function TestCommand_CommandWithDash (line 1138) | func TestCommand_CommandWithDash(t *testing.T) {
  function TestCommand_CommandWithNoFlagBeforeTerminator (line 1159) | func TestCommand_CommandWithNoFlagBeforeTerminator(t *testing.T) {
  function TestCommand_SkipFlagParsing (line 1181) | func TestCommand_SkipFlagParsing(t *testing.T) {
  function TestCommand_VisibleCommands (line 1200) | func TestCommand_VisibleCommands(t *testing.T) {
  function TestCommand_UseShortOptionHandling (line 1246) | func TestCommand_UseShortOptionHandling(t *testing.T) {
  function TestCommand_UseShortOptionHandling_missing_value (line 1271) | func TestCommand_UseShortOptionHandling_missing_value(t *testing.T) {
  function TestCommand_UseShortOptionHandlingCommand (line 1282) | func TestCommand_UseShortOptionHandlingCommand(t *testing.T) {
  function TestCommand_UseShortOptionHandlingCommand_missing_value (line 1312) | func TestCommand_UseShortOptionHandlingCommand_missing_value(t *testing....
  function TestCommand_UseShortOptionHandlingSubCommand (line 1330) | func TestCommand_UseShortOptionHandlingSubCommand(t *testing.T) {
  function TestCommand_UseShortOptionHandlingSubCommand_missing_value (line 1366) | func TestCommand_UseShortOptionHandlingSubCommand_missing_value(t *testi...
  function TestCommand_UseShortOptionAfterSliceFlag (line 1385) | func TestCommand_UseShortOptionAfterSliceFlag(t *testing.T) {
  function TestCommand_UseShortOptionWithArg (line 1416) | func TestCommand_UseShortOptionWithArg(t *testing.T) {
  function TestCommand_Float64Flag (line 1443) | func TestCommand_Float64Flag(t *testing.T) {
  function TestCommand_ParseSliceFlags (line 1460) | func TestCommand_ParseSliceFlags(t *testing.T) {
  function TestCommand_ParseSliceFlagsWithMissingValue (line 1488) | func TestCommand_ParseSliceFlagsWithMissingValue(t *testing.T) {
  function TestCommand_DefaultStdin (line 1516) | func TestCommand_DefaultStdin(t *testing.T) {
  function TestCommand_DefaultStdout (line 1523) | func TestCommand_DefaultStdout(t *testing.T) {
  function TestCommand_SetStdin (line 1530) | func TestCommand_SetStdin(t *testing.T) {
  function TestCommand_SetStdin_Subcommand (line 1547) | func TestCommand_SetStdin_Subcommand(t *testing.T) {
  function TestCommand_SetStdout (line 1574) | func TestCommand_SetStdout(t *testing.T) {
  function TestCommand_BeforeFunc (line 1587) | func TestCommand_BeforeFunc(t *testing.T) {
  function TestCommand_BeforeFuncPersistentFlag (line 1657) | func TestCommand_BeforeFuncPersistentFlag(t *testing.T) {
  function TestCommand_BeforeAfterFuncShellCompletion (line 1694) | func TestCommand_BeforeAfterFuncShellCompletion(t *testing.T) {
  function TestCommand_AfterFunc (line 1746) | func TestCommand_AfterFunc(t *testing.T) {
  function TestCommandNoHelpFlag (line 1813) | func TestCommandNoHelpFlag(t *testing.T) {
  function TestRequiredFlagCommandRunBehavior (line 1828) | func TestRequiredFlagCommandRunBehavior(t *testing.T) {
  function TestCommandHelpPrinter (line 1969) | func TestCommandHelpPrinter(t *testing.T) {
  function TestCommand_VersionPrinter (line 1987) | func TestCommand_VersionPrinter(t *testing.T) {
  function TestCommand_CommandNotFound (line 2004) | func TestCommand_CommandNotFound(t *testing.T) {
  function TestCommand_OrderOfOperations (line 2030) | func TestCommand_OrderOfOperations(t *testing.T) {
  function TestCommand_Run_CommandWithSubcommandHasHelpTopic (line 2188) | func TestCommand_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
  function TestCommand_Run_SubcommandFullPath (line 2233) | func TestCommand_Run_SubcommandFullPath(t *testing.T) {
  function TestCommand_Run_Help (line 2256) | func TestCommand_Run_Help(t *testing.T) {
  function TestCommand_Run_Version (line 2322) | func TestCommand_Run_Version(t *testing.T) {
  function TestCommand_Run_Categories (line 2347) | func TestCommand_Run_Categories(t *testing.T) {
  function TestCommand_VisibleCategories (line 2395) | func TestCommand_VisibleCategories(t *testing.T) {
  function TestCommand_Run_SubcommandDoesNotOverwriteErrorFromBefore (line 2493) | func TestCommand_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testin...
  function TestCommand_OnUsageError_WithWrongFlagValue_ForSubcommand (line 2514) | func TestCommand_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testin...
  type customBoolFlag (line 2537) | type customBoolFlag struct
    method String (line 2542) | func (c *customBoolFlag) String() string {
    method Names (line 2546) | func (c *customBoolFlag) Names() []string {
    method TakesValue (line 2550) | func (c *customBoolFlag) TakesValue() bool {
    method GetValue (line 2554) | func (c *customBoolFlag) GetValue() string {
    method GetUsage (line 2558) | func (c *customBoolFlag) GetUsage() string {
    method PreParse (line 2562) | func (c *customBoolFlag) PreParse() error {
    method PostParse (line 2566) | func (c *customBoolFlag) PostParse() error {
    method Get (line 2570) | func (c *customBoolFlag) Get() any {
    method Set (line 2577) | func (c *customBoolFlag) Set(_, _ string) error {
    method RunAction (line 2581) | func (c *customBoolFlag) RunAction(context.Context, *Command) error {
    method IsSet (line 2585) | func (c *customBoolFlag) IsSet() bool {
    method IsRequired (line 2589) | func (c *customBoolFlag) IsRequired() bool {
    method IsVisible (line 2593) | func (c *customBoolFlag) IsVisible() bool {
    method GetCategory (line 2597) | func (c *customBoolFlag) GetCategory() string {
    method GetEnvVars (line 2601) | func (c *customBoolFlag) GetEnvVars() []string {
    method GetDefaultText (line 2605) | func (c *customBoolFlag) GetDefaultText() string {
  function TestCustomFlagsUnused (line 2609) | func TestCustomFlagsUnused(t *testing.T) {
  function TestCustomFlagsUsed (line 2619) | func TestCustomFlagsUsed(t *testing.T) {
  function TestCustomHelpVersionFlags (line 2629) | func TestCustomHelpVersionFlags(t *testing.T) {
  function TestHandleExitCoder_Default (line 2647) | func TestHandleExitCoder_Default(t *testing.T) {
  function TestHandleExitCoder_Custom (line 2655) | func TestHandleExitCoder_Custom(t *testing.T) {
  function TestShellCompletionForIncompleteFlags (line 2668) | func TestShellCompletionForIncompleteFlags(t *testing.T) {
  function TestWhenExitSubCommandWithCodeThenCommandQuitUnexpectedly (line 2713) | func TestWhenExitSubCommandWithCodeThenCommandQuitUnexpectedly(t *testin...
  function buildMinimalTestCommand (line 2761) | func buildMinimalTestCommand() *Command {
  function TestSetupInitializesBothWriters (line 2767) | func TestSetupInitializesBothWriters(t *testing.T) {
  function TestSetupInitializesOnlyNilWriters (line 2776) | func TestSetupInitializesOnlyNilWriters(t *testing.T) {
  function TestFlagAction (line 2788) | func TestFlagAction(t *testing.T) {
  function TestLocalFlagError (line 3108) | func TestLocalFlagError(t *testing.T) {
  function TestPersistentFlag (line 3136) | func TestPersistentFlag(t *testing.T) {
  function TestPersistentFlagIsSet (line 3249) | func TestPersistentFlagIsSet(t *testing.T) {
  function TestRequiredFlagDelayed (line 3283) | func TestRequiredFlagDelayed(t *testing.T) {
  function TestRequiredPersistentFlag (line 3353) | func TestRequiredPersistentFlag(t *testing.T) {
  function TestFlagDuplicates (line 3379) | func TestFlagDuplicates(t *testing.T) {
  function TestShorthandCommand (line 3448) | func TestShorthandCommand(t *testing.T) {
  function TestCommand_Int (line 3507) | func TestCommand_Int(t *testing.T) {
  function TestCommand_Uint (line 3530) | func TestCommand_Uint(t *testing.T) {
  function TestCommand_Float64 (line 3553) | func TestCommand_Float64(t *testing.T) {
  function TestCommand_Duration (line 3577) | func TestCommand_Duration(t *testing.T) {
  function TestCommand_Timestamp (line 3601) | func TestCommand_Timestamp(t *testing.T) {
  function TestCommand_String (line 3638) | func TestCommand_String(t *testing.T) {
  function TestCommand_Bool (line 3664) | func TestCommand_Bool(t *testing.T) {
  function TestCommand_Value (line 3687) | func TestCommand_Value(t *testing.T) {
  function TestCommand_Value_InvalidFlagAccessHandler (line 3744) | func TestCommand_Value_InvalidFlagAccessHandler(t *testing.T) {
  function TestCommand_Args (line 3772) | func TestCommand_Args(t *testing.T) {
  function TestCommand_IsSet (line 3788) | func TestCommand_IsSet(t *testing.T) {
  function TestCommand_IsSet_fromEnv (line 3830) | func TestCommand_IsSet_fromEnv(t *testing.T) {
  function TestCommand_NumFlags (line 3878) | func TestCommand_NumFlags(t *testing.T) {
  function TestCommand_Set (line 3921) | func TestCommand_Set(t *testing.T) {
  function TestCommand_Set_InvalidFlagAccessHandler (line 3938) | func TestCommand_Set_InvalidFlagAccessHandler(t *testing.T) {
  function TestCommand_lookupFlag (line 3952) | func TestCommand_lookupFlag(t *testing.T) {
  function TestCommandAttributeAccessing (line 3982) | func TestCommandAttributeAccessing(t *testing.T) {
  function TestCheckRequiredFlags (line 4044) | func TestCheckRequiredFlags(t *testing.T) {
  function TestCheckRequiredFlagsWithOnUsageError (line 4208) | func TestCheckRequiredFlagsWithOnUsageError(t *testing.T) {
  function TestCommand_ParentCommand_Set (line 4223) | func TestCommand_ParentCommand_Set(t *testing.T) {
  function TestCommandStringDashOption (line 4238) | func TestCommandStringDashOption(t *testing.T) {
  function TestCommandReadArgsFromStdIn (line 4283) | func TestCommandReadArgsFromStdIn(t *testing.T) {
  function TestZeroValueCommand (line 4449) | func TestZeroValueCommand(t *testing.T) {
  function TestCommandInvalidName (line 4454) | func TestCommandInvalidName(t *testing.T) {
  function TestCommandCategories (line 4469) | func TestCommandCategories(t *testing.T) {
  function TestCommandSliceFlagSeparator (line 4497) | func TestCommandSliceFlagSeparator(t *testing.T) {
  function TestCommandMapKeyValueFlagSeparator (line 4512) | func TestCommandMapKeyValueFlagSeparator(t *testing.T) {
  function TestStringFlagTerminator (line 4533) | func TestStringFlagTerminator(t *testing.T) {
  function TestBoolFlagTerminator (line 4617) | func TestBoolFlagTerminator(t *testing.T) {
  function TestSliceStringFlagParsing (line 4695) | func TestSliceStringFlagParsing(t *testing.T) {
  function TestJSONExportCommand (line 4780) | func TestJSONExportCommand(t *testing.T) {
  function TestCommand_ExclusiveFlags (line 5329) | func TestCommand_ExclusiveFlags(t *testing.T) {
  function TestCommand_ExclusiveFlagsWithOnUsageError (line 5355) | func TestCommand_ExclusiveFlagsWithOnUsageError(t *testing.T) {
  function TestCommand_ExclusiveFlagsWithAfter (line 5385) | func TestCommand_ExclusiveFlagsWithAfter(t *testing.T) {
  function TestCommand_ParallelRun (line 5420) | func TestCommand_ParallelRun(t *testing.T) {
  function TestCommand_ExclusiveFlagsPersistent (line 5448) | func TestCommand_ExclusiveFlagsPersistent(t *testing.T) {

FILE: completion.go
  constant completionCommandName (line 12) | completionCommandName = "completion"
  constant completionFlag (line 15) | completionFlag = "--generate-shell-completion"
  type renderCompletion (line 18) | type renderCompletion
  constant completionDescription (line 44) | completionDescription = `Output shell completion script for bash, zsh, f...
  function buildCompletionCommand (line 60) | func buildCompletionCommand(appName string) *Command {
  function printShellCompletion (line 73) | func printShellCompletion(_ context.Context, cmd *Command, appName strin...

FILE: completion_test.go
  function TestCompletionDisable (line 13) | func TestCompletionDisable(t *testing.T) {
  function TestCompletionEnable (line 20) | func TestCompletionEnable(t *testing.T) {
  function TestCompletionEnableDiffCommandName (line 35) | func TestCompletionEnableDiffCommandName(t *testing.T) {
  function TestCompletionShell (line 45) | func TestCompletionShell(t *testing.T) {
  function TestCompletionSubcommand (line 66) | func TestCompletionSubcommand(t *testing.T) {
  type mockWriter (line 190) | type mockWriter struct
    method Write (line 194) | func (mw *mockWriter) Write(p []byte) (int, error) {
  function TestCompletionInvalidShell (line 201) | func TestCompletionInvalidShell(t *testing.T) {

FILE: docs.go
  function prefixFor (line 10) | func prefixFor(name string) (prefix string) {
  function unquoteUsage (line 21) | func unquoteUsage(usage string) (string, string) {
  function prefixedNames (line 37) | func prefixedNames(names []string, placeholder string) string {
  function envFormat (line 55) | func envFormat(envVars []string, prefix, sep, suffix string) string {
  function defaultEnvFormat (line 62) | func defaultEnvFormat(envVars []string) string {
  function withEnvHint (line 66) | func withEnvHint(envVars []string, str string) string {
  function withFileHint (line 76) | func withFileHint(filePath, str string) string {
  function formatDefault (line 84) | func formatDefault(format string) string {
  function stringifyFlag (line 88) | func stringifyFlag(f Flag) string {

FILE: errors.go
  type MultiError (line 18) | type MultiError interface
  function newMultiError (line 24) | func newMultiError(err ...error) MultiError {
  type multiError (line 29) | type multiError
    method Error (line 32) | func (m *multiError) Error() string {
    method Errors (line 42) | func (m *multiError) Errors() []error {
  type requiredFlagsErr (line 48) | type requiredFlagsErr interface
  type errRequiredFlags (line 52) | type errRequiredFlags struct
    method Error (line 56) | func (e *errRequiredFlags) Error() string {
  type mutuallyExclusiveGroup (line 64) | type mutuallyExclusiveGroup struct
    method Error (line 69) | func (e *mutuallyExclusiveGroup) Error() string {
  type mutuallyExclusiveGroupRequiredFlag (line 73) | type mutuallyExclusiveGroupRequiredFlag struct
    method Error (line 77) | func (e *mutuallyExclusiveGroupRequiredFlag) Error() string {
  type ErrorFormatter (line 91) | type ErrorFormatter interface
  type ExitCoder (line 96) | type ExitCoder interface
  type exitError (line 101) | type exitError struct
    method Error (line 131) | func (ee *exitError) Error() string {
    method ExitCode (line 135) | func (ee *exitError) ExitCode() int {
  function Exit (line 113) | func Exit(message any, exitCode int) ExitCoder {
  function HandleExitCoder (line 147) | func HandleExitCoder(err error) {
  function handleMultiError (line 169) | func handleMultiError(multiErr MultiError) int {

FILE: errors_test.go
  function TestHandleExitCoder_nil (line 12) | func TestHandleExitCoder_nil(t *testing.T) {
  function TestHandleExitCoder_ExitCoder (line 31) | func TestHandleExitCoder_ExitCoder(t *testing.T) {
  function TestHandleExitCoder_ErrorExitCoder (line 50) | func TestHandleExitCoder_ErrorExitCoder(t *testing.T) {
  function TestHandleExitCoder_MultiErrorWithExitCoder (line 69) | func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
  type exitFormatter (line 92) | type exitFormatter struct
    method Format (line 96) | func (f *exitFormatter) Format(s fmt.State, verb rune) {
    method ExitCode (line 100) | func (f *exitFormatter) ExitCode() int {
    method Error (line 104) | func (f *exitFormatter) Error() string {
  function TestHandleExitCoder_ErrorFormatter (line 108) | func TestHandleExitCoder_ErrorFormatter(t *testing.T) {
  function TestHandleExitCoder_MultiErrorWithoutExitCoder (line 140) | func TestHandleExitCoder_MultiErrorWithoutExitCoder(t *testing.T) {
  type ErrorWithFormat (line 161) | type ErrorWithFormat struct
    method Format (line 169) | func (f *ErrorWithFormat) Format(s fmt.State, verb rune) {
  function NewErrorWithFormat (line 165) | func NewErrorWithFormat(m string) *ErrorWithFormat {
  function TestHandleExitCoder_ErrorWithFormat (line 173) | func TestHandleExitCoder_ErrorWithFormat(t *testing.T) {
  function TestHandleExitCoder_MultiErrorWithFormat (line 195) | func TestHandleExitCoder_MultiErrorWithFormat(t *testing.T) {
  function TestMultiErrorErrorsCopy (line 214) | func TestMultiErrorErrorsCopy(t *testing.T) {
  function TestErrRequiredFlags_Error (line 224) | func TestErrRequiredFlags_Error(t *testing.T) {

FILE: examples/example-cli/example-cli.go
  function main (line 11) | func main() {

FILE: examples/example-hello-world/example-hello-world.go
  function main (line 7) | func main() {

FILE: examples_test.go
  function ExampleCommand_Run (line 16) | func ExampleCommand_Run() {
  function ExampleCommand_Run_subcommand (line 46) | func ExampleCommand_Run_subcommand() {
  function ExampleCommand_Run_appHelp (line 89) | func ExampleCommand_Run_appHelp() {
  function ExampleCommand_Run_commandHelp (line 151) | func ExampleCommand_Run_commandHelp() {
  function ExampleCommand_Run_noAction (line 194) | func ExampleCommand_Run_noAction() {
  function ExampleCommand_Run_subcommandNoAction (line 212) | func ExampleCommand_Run_subcommandNoAction() {
  function ExampleCommand_Run_shellComplete_bash_withShortFlag (line 244) | func ExampleCommand_Run_shellComplete_bash_withShortFlag() {
  function ExampleCommand_Run_shellComplete_bash_withLongFlag (line 271) | func ExampleCommand_Run_shellComplete_bash_withLongFlag() {
  function ExampleCommand_Run_shellComplete_bash_withMultipleLongFlag (line 303) | func ExampleCommand_Run_shellComplete_bash_withMultipleLongFlag() {
  function ExampleCommand_Run_shellComplete_bash (line 338) | func ExampleCommand_Run_shellComplete_bash() {
  function ExampleCommand_Run_shellComplete_zsh (line 375) | func ExampleCommand_Run_shellComplete_zsh() {
  function ExampleCommand_Run_shellComplete_fish (line 412) | func ExampleCommand_Run_shellComplete_fish() {
  function ExampleCommand_Run_sliceValues (line 449) | func ExampleCommand_Run_sliceValues() {
  function ExampleCommand_Run_mapValues (line 484) | func ExampleCommand_Run_mapValues() {
  function ExampleBoolWithInverseFlag (line 515) | func ExampleBoolWithInverseFlag() {
  function ExampleCommand_Suggest (line 546) | func ExampleCommand_Suggest() {
  function ExampleCommand_Suggest_command (line 574) | func ExampleCommand_Suggest_command() {

FILE: fish.go
  method ToFishCompletion (line 13) | func (cmd *Command) ToFishCompletion() (string, error) {
  type fishCommandCompletionTemplate (line 21) | type fishCommandCompletionTemplate struct
  method writeFishCompletionTemplate (line 27) | func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error {
  function prepareFishCommands (line 67) | func prepareFishCommands(binary string, parent *Command) []string {
  function prepareFishFlags (line 122) | func prepareFishFlags(binary string, owner *Command) []string {
  function fishAddFileFlag (line 165) | func fishAddFileFlag(flag Flag, completion *strings.Builder) {
  function fishSubcommandHelper (line 179) | func fishSubcommandHelper(binary string, command *Command, siblings []*C...
  function fishFlagHelper (line 196) | func fishFlagHelper(binary string, command *Command) string {
  function commandAncestry (line 204) | func commandAncestry(command *Command) string {
  function escapeSingleQuotes (line 219) | func escapeSingleQuotes(input string) string {

FILE: fish_test.go
  function TestFishCompletion (line 12) | func TestFishCompletion(t *testing.T) {
  function TestFishCompletionShellComplete (line 44) | func TestFishCompletionShellComplete(t *testing.T) {

FILE: flag.go
  constant defaultPlaceholder (line 11) | defaultPlaceholder = "value"
  constant defaultSliceFlagSeparator (line 14) | defaultSliceFlagSeparator       = ","
  constant defaultMapFlagKeyValueSeparator (line 15) | defaultMapFlagKeyValueSeparator = "="
  constant disableSliceFlagSeparator (line 16) | disableSliceFlagSeparator       = false
  type Serializer (line 56) | type Serializer interface
  type FlagsByName (line 73) | type FlagsByName
    method Len (line 75) | func (f FlagsByName) Len() int {
    method Less (line 79) | func (f FlagsByName) Less(i, j int) bool {
    method Swap (line 83) | func (f FlagsByName) Swap(i, j int) {
  type ActionableFlag (line 88) | type ActionableFlag interface
  type Flag (line 95) | type Flag interface
  type RequiredFlag (line 120) | type RequiredFlag interface
  type DocGenerationFlag (line 126) | type DocGenerationFlag interface
  type DocGenerationMultiValueFlag (line 151) | type DocGenerationMultiValueFlag interface
  type Countable (line 160) | type Countable interface
  type VisibleFlag (line 165) | type VisibleFlag interface
  type CategorizableFlag (line 172) | type CategorizableFlag interface
  type LocalFlag (line 182) | type LocalFlag interface
  function visibleFlags (line 186) | func visibleFlags(fl []Flag) []Flag {
  function FlagNames (line 196) | func FlagNames(name string, aliases []string) []string {
  function hasFlag (line 210) | func hasFlag(flags []Flag, fl Flag) bool {
  function flagSplitMultiValues (line 220) | func flagSplitMultiValues(val string, sliceSeparator string, disableSlic...

FILE: flag_bool.go
  type BoolConfig (line 11) | type BoolConfig struct
  type boolValue (line 22) | type boolValue struct
    method Create (line 40) | func (b boolValue) Create(val bool, p *bool, c BoolConfig) Value {
    method ToString (line 52) | func (b boolValue) ToString(value bool) string {
    method Set (line 59) | func (b *boolValue) Set(s string) error {
    method Get (line 72) | func (b *boolValue) Get() interface{} { return *b.destination }
    method String (line 74) | func (b *boolValue) String() string {
    method IsBoolFlag (line 78) | func (b *boolValue) IsBoolFlag() bool { return true }
  method Bool (line 27) | func (cmd *Command) Bool(name string) bool {

FILE: flag_bool_with_inverse.go
  type BoolWithInverseFlag (line 12) | type BoolWithInverseFlag struct
    method IsSet (line 42) | func (bif *BoolWithInverseFlag) IsSet() bool {
    method Get (line 46) | func (bif *BoolWithInverseFlag) Get() any {
    method RunAction (line 50) | func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Co...
    method IsLocal (line 58) | func (bif *BoolWithInverseFlag) IsLocal() bool {
    method inversePrefix (line 62) | func (bif *BoolWithInverseFlag) inversePrefix() string {
    method PreParse (line 70) | func (bif *BoolWithInverseFlag) PreParse() error {
    method PostParse (line 95) | func (bif *BoolWithInverseFlag) PostParse() error {
    method Set (line 117) | func (bif *BoolWithInverseFlag) Set(name, val string) error {
    method Names (line 148) | func (bif *BoolWithInverseFlag) Names() []string {
    method IsRequired (line 158) | func (bif *BoolWithInverseFlag) IsRequired() bool {
    method IsVisible (line 162) | func (bif *BoolWithInverseFlag) IsVisible() bool {
    method String (line 170) | func (bif *BoolWithInverseFlag) String() string {
    method IsBoolFlag (line 186) | func (bif *BoolWithInverseFlag) IsBoolFlag() bool {
    method Count (line 191) | func (bif *BoolWithInverseFlag) Count() int {
    method GetDefaultText (line 196) | func (bif *BoolWithInverseFlag) GetDefaultText() string {
    method GetCategory (line 204) | func (bif *BoolWithInverseFlag) GetCategory() string {
    method SetCategory (line 208) | func (bif *BoolWithInverseFlag) SetCategory(c string) {
    method GetUsage (line 213) | func (bif *BoolWithInverseFlag) GetUsage() string {
    method GetEnvVars (line 218) | func (bif *BoolWithInverseFlag) GetEnvVars() []string {
    method GetValue (line 224) | func (bif *BoolWithInverseFlag) GetValue() string {
    method TakesValue (line 228) | func (bif *BoolWithInverseFlag) TakesValue() bool {
    method IsDefaultVisible (line 233) | func (bif *BoolWithInverseFlag) IsDefaultVisible() bool {
    method TypeName (line 238) | func (bif *BoolWithInverseFlag) TypeName() string {

FILE: flag_bool_with_inverse_test.go
  type boolWithInverseTestCase (line 14) | type boolWithInverseTestCase struct
    method Run (line 22) | func (tc *boolWithInverseTestCase) Run(t *testing.T, flagWithInverse *...
  function runBoolWithInverseFlagTests (line 48) | func runBoolWithInverseFlagTests(t *testing.T, newFlagMethod func() *Boo...
  function TestBoolWithInverseBasic (line 73) | func TestBoolWithInverseBasic(t *testing.T) {
  function TestBoolWithInverseAction (line 108) | func TestBoolWithInverseAction(t *testing.T) {
  function TestBoolWithInverseAlias (line 154) | func TestBoolWithInverseAlias(t *testing.T) {
  function TestBoolWithInverseEnvVars (line 190) | func TestBoolWithInverseEnvVars(t *testing.T) {
  function TestBoolWithInverseWithPrefix (line 254) | func TestBoolWithInverseWithPrefix(t *testing.T) {
  function TestBoolWithInverseRequired (line 294) | func TestBoolWithInverseRequired(t *testing.T) {
  function TestBoolWithInverseNames (line 326) | func TestBoolWithInverseNames(t *testing.T) {
  function TestBoolWithInverseString (line 341) | func TestBoolWithInverseString(t *testing.T) {
  function TestBoolWithInverseDestination (line 416) | func TestBoolWithInverseDestination(t *testing.T) {
  function TestBoolWithInverseFlag_SatisfiesRequiredFlagInterface (line 512) | func TestBoolWithInverseFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
  function TestBoolWithInverseFlag_SatisfiesVisibleFlagInterface (line 518) | func TestBoolWithInverseFlag_SatisfiesVisibleFlagInterface(t *testing.T) {

FILE: flag_duration.go
  type durationValue (line 11) | type durationValue
    method Create (line 15) | func (d durationValue) Create(val time.Duration, p *time.Duration, c N...
    method ToString (line 20) | func (d durationValue) ToString(val time.Duration) string {
    method Set (line 27) | func (d *durationValue) Set(s string) error {
    method Get (line 36) | func (d *durationValue) Get() any { return time.Duration(*d) }
    method String (line 38) | func (d *durationValue) String() string {
  method Duration (line 42) | func (cmd *Command) Duration(name string) time.Duration {

FILE: flag_ext.go
  type extFlag (line 5) | type extFlag struct
    method PreParse (line 9) | func (e *extFlag) PreParse() error {
    method PostParse (line 17) | func (e *extFlag) PostParse() error {
    method Set (line 21) | func (e *extFlag) Set(_ string, val string) error {
    method Get (line 25) | func (e *extFlag) Get() any {
    method Names (line 29) | func (e *extFlag) Names() []string {
    method IsSet (line 33) | func (e *extFlag) IsSet() bool {
    method String (line 37) | func (e *extFlag) String() string {
    method IsVisible (line 41) | func (e *extFlag) IsVisible() bool {
    method TakesValue (line 45) | func (e *extFlag) TakesValue() bool {
    method GetUsage (line 49) | func (e *extFlag) GetUsage() string {
    method GetValue (line 53) | func (e *extFlag) GetValue() string {
    method GetDefaultText (line 57) | func (e *extFlag) GetDefaultText() string {
    method GetEnvVars (line 61) | func (e *extFlag) GetEnvVars() []string {

FILE: flag_float.go
  type floatValue (line 15) | type floatValue struct
  method Create (line 21) | func (f floatValue[T]) Create(val T, p *T, c NoConfig) Value {
  method ToString (line 27) | func (f floatValue[T]) ToString(b T) string {
  method Set (line 34) | func (f *floatValue[T]) Set(s string) error {
  method Get (line 43) | func (f *floatValue[T]) Get() any { return *f.val }
  method String (line 45) | func (f *floatValue[T]) String() string {
  method Float (line 51) | func (cmd *Command) Float(name string) float64 {
  method Float32 (line 57) | func (cmd *Command) Float32(name string) float32 {
  method Float64 (line 63) | func (cmd *Command) Float64(name string) float64 {
  function getFloat (line 67) | func getFloat[T float32 | float64](cmd *Command, name string) T {

FILE: flag_float_slice.go
  method FloatSlice (line 20) | func (cmd *Command) FloatSlice(name string) []float64 {
  method Float32Slice (line 26) | func (cmd *Command) Float32Slice(name string) []float32 {
  method Float64Slice (line 32) | func (cmd *Command) Float64Slice(name string) []float64 {

FILE: flag_float_slice_test.go
  function TestCommand_FloatSlice (line 11) | func TestCommand_FloatSlice(t *testing.T) {
  function TestCommand_Float32Slice (line 60) | func TestCommand_Float32Slice(t *testing.T) {
  function TestCommand_Float64Slice (line 109) | func TestCommand_Float64Slice(t *testing.T) {

FILE: flag_float_test.go
  function Test_FloatFlag (line 11) | func Test_FloatFlag(t *testing.T) {
  function Test_Float32Flag (line 64) | func Test_Float32Flag(t *testing.T) {
  function Test_Float64Flag (line 118) | func Test_Float64Flag(t *testing.T) {
  function Test_floatValue_String (line 171) | func Test_floatValue_String(t *testing.T) {

FILE: flag_generic.go
  type genericValue (line 6) | type genericValue struct
    method Create (line 12) | func (f genericValue) Create(val Value, p *Value, c NoConfig) Value {
    method ToString (line 19) | func (f genericValue) ToString(b Value) string {
    method Set (line 26) | func (f *genericValue) Set(s string) error {
    method Get (line 33) | func (f *genericValue) Get() any {
    method String (line 40) | func (f *genericValue) String() string {
    method IsBoolFlag (line 47) | func (f *genericValue) IsBoolFlag() bool {
  method Generic (line 57) | func (cmd *Command) Generic(name string) Value {

FILE: flag_impl.go
  type Value (line 13) | type Value interface
  type boolFlag (line 18) | type boolFlag interface
  type multiValueParsingConfig (line 22) | type multiValueParsingConfig struct
  type multiValueParsingConfigSetter (line 31) | type multiValueParsingConfigSetter interface
  type ValueCreator (line 41) | type ValueCreator interface
  type NoConfig (line 47) | type NoConfig struct
  type FlagBase (line 56) | type FlagBase struct
  method GetValue (line 86) | func (f *FlagBase[T, C, V]) GetValue() string {
  method TypeName (line 92) | func (f *FlagBase[T, C, V]) TypeName() string {
  method PostParse (line 128) | func (f *FlagBase[T, C, V]) PostParse() error {
  method setMultiValueParsingConfig (line 152) | func (f *FlagBase[T, C, V]) setMultiValueParsingConfig(c multiValueParsi...
  method PreParse (line 159) | func (f *FlagBase[T, C, V]) PreParse() error {
  method Set (line 179) | func (f *FlagBase[T, C, V]) Set(_ string, val string) error {
  method Get (line 212) | func (f *FlagBase[T, C, V]) Get() any {
  method IsDefaultVisible (line 220) | func (f *FlagBase[T, C, V]) IsDefaultVisible() bool {
  method String (line 225) | func (f *FlagBase[T, C, V]) String() string {
  method IsSet (line 230) | func (f *FlagBase[T, C, V]) IsSet() bool {
  method Names (line 235) | func (f *FlagBase[T, C, V]) Names() []string {
  method IsRequired (line 240) | func (f *FlagBase[T, C, V]) IsRequired() bool {
  method IsVisible (line 245) | func (f *FlagBase[T, C, V]) IsVisible() bool {
  method GetCategory (line 250) | func (f *FlagBase[T, C, V]) GetCategory() string {
  method SetCategory (line 254) | func (f *FlagBase[T, C, V]) SetCategory(c string) {
  method GetUsage (line 259) | func (f *FlagBase[T, C, V]) GetUsage() string {
  method GetEnvVars (line 264) | func (f *FlagBase[T, C, V]) GetEnvVars() []string {
  method TakesValue (line 269) | func (f *FlagBase[T, C, V]) TakesValue() bool {
  method GetDefaultText (line 275) | func (f *FlagBase[T, C, V]) GetDefaultText() string {
  method RunAction (line 280) | func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command)...
  method IsMultiValueFlag (line 290) | func (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool {
  method IsLocal (line 300) | func (f *FlagBase[T, C, VC]) IsLocal() bool {
  method IsBoolFlag (line 305) | func (f *FlagBase[T, C, VC]) IsBoolFlag() bool {
  method Count (line 311) | func (f *FlagBase[T, C, VC]) Count() int {

FILE: flag_int.go
  type IntegerConfig (line 17) | type IntegerConfig struct
  type intValue (line 22) | type intValue struct
  method Create (line 29) | func (i intValue[T]) Create(val T, p *T, c IntegerConfig) Value {
  method ToString (line 38) | func (i intValue[T]) ToString(b T) string {
  method Set (line 45) | func (i *intValue[T]) Set(s string) error {
  method Get (line 54) | func (i *intValue[T]) Get() any { return *i.val }
  method String (line 56) | func (i *intValue[T]) String() string {
  method Int (line 67) | func (cmd *Command) Int(name string) int {
  method Int8 (line 73) | func (cmd *Command) Int8(name string) int8 {
  method Int16 (line 79) | func (cmd *Command) Int16(name string) int16 {
  method Int32 (line 85) | func (cmd *Command) Int32(name string) int32 {
  method Int64 (line 91) | func (cmd *Command) Int64(name string) int64 {
  function getInt (line 95) | func getInt[T int | int8 | int16 | int32 | int64](cmd *Command, name str...

FILE: flag_int_slice.go
  method IntSlice (line 26) | func (cmd *Command) IntSlice(name string) []int {
  method Int8Slice (line 32) | func (cmd *Command) Int8Slice(name string) []int8 {
  method Int16Slice (line 38) | func (cmd *Command) Int16Slice(name string) []int16 {
  method Int32Slice (line 44) | func (cmd *Command) Int32Slice(name string) []int32 {
  method Int64Slice (line 50) | func (cmd *Command) Int64Slice(name string) []int64 {

FILE: flag_int_slice_test.go
  function TestCommand_IntSlice (line 11) | func TestCommand_IntSlice(t *testing.T) {
  function TestCommand_Int8Slice (line 60) | func TestCommand_Int8Slice(t *testing.T) {
  function TestCommand_Int16Slice (line 109) | func TestCommand_Int16Slice(t *testing.T) {
  function TestCommand_Int32Slice (line 158) | func TestCommand_Int32Slice(t *testing.T) {
  function TestCommand_Int64Slice (line 207) | func TestCommand_Int64Slice(t *testing.T) {

FILE: flag_int_test.go
  function TestIntFlag (line 12) | func TestIntFlag(t *testing.T) {
  function TestInt8Flag (line 65) | func TestInt8Flag(t *testing.T) {
  function TestInt16Flag (line 118) | func TestInt16Flag(t *testing.T) {
  function TestInt32Flag (line 179) | func TestInt32Flag(t *testing.T) {
  function TestInt64Flag (line 241) | func TestInt64Flag(t *testing.T) {
  function TestIntFlagExt (line 294) | func TestIntFlagExt(t *testing.T) {

FILE: flag_map_impl.go
  type MapBase (line 12) | type MapBase struct
  method Create (line 19) | func (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C...
  function NewMapBase (line 34) | func NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string...
  method setMultiValueParsingConfig (line 41) | func (i *MapBase[T, C, VC]) setMultiValueParsingConfig(c multiValueParsi...
  method Set (line 53) | func (i *MapBase[T, C, VC]) Set(value string) error {
  method String (line 94) | func (i *MapBase[T, C, VC]) String() string {
  method Serialize (line 104) | func (i *MapBase[T, C, VC]) Serialize() string {
  method Value (line 110) | func (i *MapBase[T, C, VC]) Value() map[string]T {
  method Get (line 118) | func (i *MapBase[T, C, VC]) Get() interface{} {
  method ToString (line 122) | func (i MapBase[T, C, VC]) ToString(t map[string]T) string {
  function sortedKeys (line 131) | func sortedKeys[T any](dict map[string]T) []string {

FILE: flag_mutex.go
  type MutuallyExclusiveFlags (line 8) | type MutuallyExclusiveFlags struct
    method check (line 19) | func (grp MutuallyExclusiveFlags) check(_ *Command) error {
    method propagateCategory (line 46) | func (grp MutuallyExclusiveFlags) propagateCategory() {

FILE: flag_mutex_test.go
  function newCommand (line 10) | func newCommand() *Command {
  function TestFlagMutuallyExclusiveFlags (line 40) | func TestFlagMutuallyExclusiveFlags(t *testing.T) {

FILE: flag_number_slice.go
  type numberType (line 3) | type numberType interface
  function getNumberSlice (line 7) | func getNumberSlice[T numberType](cmd *Command, name string) []T {

FILE: flag_number_slice_test.go
  function Test_getNumberSlice_int64 (line 11) | func Test_getNumberSlice_int64(t *testing.T) {
  function Test_getNumberSlice_float64 (line 29) | func Test_getNumberSlice_float64(t *testing.T) {

FILE: flag_slice_base.go
  type SliceBase (line 11) | type SliceBase struct
  method Create (line 19) | func (i SliceBase[T, C, VC]) Create(val []T, p *[]T, c C) Value {
  function NewSliceBase (line 32) | func NewSliceBase[T any, C any, VC ValueCreator[T, C]](defaults ...T) *S...
  method setMultiValueParsingConfig (line 39) | func (i *SliceBase[T, C, VC]) setMultiValueParsingConfig(c multiValuePar...
  method Set (line 46) | func (i *SliceBase[T, C, VC]) Set(value string) error {
  method String (line 84) | func (i *SliceBase[T, C, VC]) String() string {
  method Serialize (line 94) | func (i *SliceBase[T, C, VC]) Serialize() string {
  method Value (line 100) | func (i *SliceBase[T, C, VC]) Value() []T {
  method Get (line 108) | func (i *SliceBase[T, C, VC]) Get() interface{} {
  method ToString (line 112) | func (i SliceBase[T, C, VC]) ToString(t []T) string {

FILE: flag_string.go
  type StringConfig (line 11) | type StringConfig struct
  type stringValue (line 17) | type stringValue struct
    method Create (line 24) | func (s stringValue) Create(val string, p *string, c StringConfig) Val...
    method ToString (line 32) | func (s stringValue) ToString(val string) string {
    method Set (line 39) | func (s *stringValue) Set(val string) error {
    method Get (line 47) | func (s *stringValue) Get() any { return *s.destination }
    method String (line 49) | func (s *stringValue) String() string {
  method String (line 56) | func (cmd *Command) String(name string) string {

FILE: flag_string_map.go
  method StringMap (line 12) | func (cmd *Command) StringMap(name string) map[string]string {

FILE: flag_string_slice.go
  method StringSlice (line 12) | func (cmd *Command) StringSlice(name string) []string {

FILE: flag_test.go
  type Parser (line 21) | type Parser
    method Set (line 23) | func (p *Parser) Set(value string) error {
    method String (line 35) | func (p *Parser) String() string {
    method Get (line 39) | func (p *Parser) Get() interface{} {
  function TestBoolFlagHelpOutput (line 51) | func TestBoolFlagHelpOutput(t *testing.T) {
  function TestBoolFlagApply_SetsAllNames (line 59) | func TestBoolFlagApply_SetsAllNames(t *testing.T) {
  function TestBoolFlagValueFromCommand (line 71) | func TestBoolFlagValueFromCommand(t *testing.T) {
  function TestBoolFlagApply_SetsCount (line 88) | func TestBoolFlagApply_SetsCount(t *testing.T) {
  function TestBoolFlagCountFromCommand (line 101) | func TestBoolFlagCountFromCommand(t *testing.T) {
  function TestFlagsFromEnv (line 156) | func TestFlagsFromEnv(t *testing.T) {
  type nodocFlag (line 458) | type nodocFlag struct
  function TestFlagStringifying (line 464) | func TestFlagStringifying(t *testing.T) {
  function TestStringFlagHelpOutput (line 653) | func TestStringFlagHelpOutput(t *testing.T) {
  function TestStringFlagDefaultText (line 660) | func TestStringFlagDefaultText(t *testing.T) {
  function TestStringFlagWithEnvVarHelpOutput (line 666) | func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestStringFlagApply_SetsAllNames (line 708) | func TestStringFlagApply_SetsAllNames(t *testing.T) {
  function TestStringFlagValueFromCommand (line 721) | func TestStringFlagValueFromCommand(t *testing.T) {
  function TestStringSliceFlagHelpOutput (line 780) | func TestStringSliceFlagHelpOutput(t *testing.T) {
  function TestStringSliceFlagWithEnvVarHelpOutput (line 787) | func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestStringSliceFlagApply_SetsAllNames (line 801) | func TestStringSliceFlagApply_SetsAllNames(t *testing.T) {
  function TestStringSliceFlagApply_UsesEnvValues_noDefault (line 813) | func TestStringSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  function TestStringSliceFlagApply_UsesEnvValues_withDefault (line 827) | func TestStringSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  function TestStringSliceFlagApply_DefaultValueWithDestination (line 841) | func TestStringSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  function TestStringSliceFlagValueFromCommand (line 857) | func TestStringSliceFlagValueFromCommand(t *testing.T) {
  function TestIntFlagHelpOutput (line 879) | func TestIntFlagHelpOutput(t *testing.T) {
  function TestIntFlagWithEnvVarHelpOutput (line 886) | func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestIntFlagApply_SetsAllNames (line 900) | func TestIntFlagApply_SetsAllNames(t *testing.T) {
  function TestIntFlagValueFromCommand (line 912) | func TestIntFlagValueFromCommand(t *testing.T) {
  function TestUintFlagHelpOutput (line 931) | func TestUintFlagHelpOutput(t *testing.T) {
  function TestUintFlagWithEnvVarHelpOutput (line 938) | func TestUintFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestUintFlagValueFromCommand (line 952) | func TestUintFlagValueFromCommand(t *testing.T) {
  function TestUint64FlagHelpOutput (line 971) | func TestUint64FlagHelpOutput(t *testing.T) {
  function TestUint64FlagWithEnvVarHelpOutput (line 978) | func TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {
  function TestUint64FlagValueFromCommand (line 992) | func TestUint64FlagValueFromCommand(t *testing.T) {
  function TestDurationFlagHelpOutput (line 1011) | func TestDurationFlagHelpOutput(t *testing.T) {
  function TestDurationFlagWithEnvVarHelpOutput (line 1018) | func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestDurationFlagApply_SetsAllNames (line 1032) | func TestDurationFlagApply_SetsAllNames(t *testing.T) {
  function TestDurationFlagValueFromCommand (line 1044) | func TestDurationFlagValueFromCommand(t *testing.T) {
  function TestIntSliceFlagHelpOutput (line 1066) | func TestIntSliceFlagHelpOutput(t *testing.T) {
  function TestIntSliceFlagWithEnvVarHelpOutput (line 1073) | func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestIntSliceFlagApply_SetsAllNames (line 1087) | func TestIntSliceFlagApply_SetsAllNames(t *testing.T) {
  function TestIntSliceFlagApply_UsesEnvValues_noDefault (line 1098) | func TestIntSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  function TestIntSliceFlagApply_UsesEnvValues_withDefault (line 1113) | func TestIntSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  function TestIntSliceFlagApply_DefaultValueWithDestination (line 1128) | func TestIntSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  function TestIntSliceFlagApply_ParentContext (line 1143) | func TestIntSliceFlagApply_ParentContext(t *testing.T) {
  function TestIntSliceFlag_SetFromParentCommand (line 1161) | func TestIntSliceFlag_SetFromParentCommand(t *testing.T) {
  function TestIntSliceFlagValueFromCommand (line 1175) | func TestIntSliceFlagValueFromCommand(t *testing.T) {
  function TestUintSliceFlagHelpOutput (line 1204) | func TestUintSliceFlagHelpOutput(t *testing.T) {
  function TestUintSliceFlagWithEnvVarHelpOutput (line 1213) | func TestUintSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestUintSliceFlagApply_SetsAllNames (line 1227) | func TestUintSliceFlagApply_SetsAllNames(t *testing.T) {
  function TestUintSliceFlagApply_UsesEnvValues_noDefault (line 1238) | func TestUintSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  function TestUintSliceFlagApply_UsesEnvValues_withDefault (line 1252) | func TestUintSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  function TestUintSliceFlagApply_DefaultValueWithDestination (line 1267) | func TestUintSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  function TestUint64SliceFlagApply_ParentContext (line 1282) | func TestUint64SliceFlagApply_ParentContext(t *testing.T) {
  function TestUintSliceFlag_SetFromParentCommand (line 1302) | func TestUintSliceFlag_SetFromParentCommand(t *testing.T) {
  function TestUintSliceFlag_ReturnNil (line 1320) | func TestUintSliceFlag_ReturnNil(t *testing.T) {
  function TestUint64SliceFlagHelpOutput (line 1354) | func TestUint64SliceFlagHelpOutput(t *testing.T) {
  function TestUint64SliceFlagWithEnvVarHelpOutput (line 1361) | func TestUint64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestUint64SliceFlagApply_SetsAllNames (line 1375) | func TestUint64SliceFlagApply_SetsAllNames(t *testing.T) {
  function TestUint64SliceFlagApply_UsesEnvValues_noDefault (line 1386) | func TestUint64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  function TestUint64SliceFlagApply_UsesEnvValues_withDefault (line 1398) | func TestUint64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  function TestUint64SliceFlagApply_DefaultValueWithDestination (line 1411) | func TestUint64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  function TestUint64SliceFlagApply_ParentCommand (line 1428) | func TestUint64SliceFlagApply_ParentCommand(t *testing.T) {
  function TestUint64SliceFlag_SetFromParentCommand (line 1448) | func TestUint64SliceFlag_SetFromParentCommand(t *testing.T) {
  function TestUint64SliceFlag_ReturnNil (line 1464) | func TestUint64SliceFlag_ReturnNil(t *testing.T) {
  function TestFloat64FlagHelpOutput (line 1488) | func TestFloat64FlagHelpOutput(t *testing.T) {
  function TestFloat64FlagWithEnvVarHelpOutput (line 1495) | func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
  function TestFloat64FlagApply_SetsAllNames (line 1509) | func TestFloat64FlagApply_SetsAllNames(t *testing.T) {
  function TestFloat64FlagValueFromCommand (line 1522) | func TestFloat64FlagValueFromCommand(t *testing.T) {
  function TestFloat64SliceFlagHelpOutput (line 1549) | func TestFloat64SliceFlagHelpOutput(t *testing.T) {
  function TestFloat64SliceFlagWithEnvVarHelpOutput (line 1556) | func TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestFloat64SliceFlagApply_SetsAllNames (line 1569) | func TestFloat64SliceFlagApply_SetsAllNames(t *testing.T) {
  function TestFloat64SliceFlagApply_UsesEnvValues_noDefault (line 1580) | func TestFloat64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  function TestFloat64SliceFlagApply_UsesEnvValues_withDefault (line 1593) | func TestFloat64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  function TestFloat64SliceFlagApply_DefaultValueWithDestination (line 1607) | func TestFloat64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  function TestFloat64SliceFlagValueFromCommand (line 1622) | func TestFloat64SliceFlagValueFromCommand(t *testing.T) {
  function TestFloat64SliceFlagApply_ParentCommand (line 1635) | func TestFloat64SliceFlagApply_ParentCommand(t *testing.T) {
  function TestGenericFlagHelpOutput (line 1661) | func TestGenericFlagHelpOutput(t *testing.T) {
  function TestGenericFlagWithEnvVarHelpOutput (line 1668) | func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestGenericFlagApply_SetsAllNames (line 1682) | func TestGenericFlagApply_SetsAllNames(t *testing.T) {
  function TestGenericFlagValueFromCommand (line 1693) | func TestGenericFlagValueFromCommand(t *testing.T) {
  function TestParseGenericFromEnv (line 1706) | func TestParseGenericFromEnv(t *testing.T) {
  function TestFlagActionFromEnv (line 1730) | func TestFlagActionFromEnv(t *testing.T) {
  function TestParseShortOptionBoolError (line 1752) | func TestParseShortOptionBoolError(t *testing.T) {
  function TestParseShortOptionIntError (line 1764) | func TestParseShortOptionIntError(t *testing.T) {
  function TestParseMultiString (line 1775) | func TestParseMultiString(t *testing.T) {
  function TestParseDestinationString (line 1788) | func TestParseDestinationString(t *testing.T) {
  function TestParseMultiStringFromEnv (line 1804) | func TestParseMultiStringFromEnv(t *testing.T) {
  function TestParseMultiStringFromEnvCascade (line 1819) | func TestParseMultiStringFromEnvCascade(t *testing.T) {
  function TestParseMultiStringSlice (line 1834) | func TestParseMultiStringSlice(t *testing.T) {
  function TestParseMultiStringSliceWithDefaults (line 1848) | func TestParseMultiStringSliceWithDefaults(t *testing.T) {
  function TestParseMultiStringSliceWithDestination (line 1862) | func TestParseMultiStringSliceWithDestination(t *testing.T) {
  function TestParseMultiStringSliceWithDestinationAndEnv (line 1877) | func TestParseMultiStringSliceWithDestinationAndEnv(t *testing.T) {
  function TestParseMultiFloat64SliceWithDestinationAndEnv (line 1893) | func TestParseMultiFloat64SliceWithDestinationAndEnv(t *testing.T) {
  function TestParseMultiIntSliceWithDestinationAndEnv (line 1909) | func TestParseMultiIntSliceWithDestinationAndEnv(t *testing.T) {
  function TestParseMultiStringSliceWithDefaultsUnset (line 1925) | func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
  function TestParseMultiStringSliceFromEnv (line 1939) | func TestParseMultiStringSliceFromEnv(t *testing.T) {
  function TestParseMultiStringSliceFromEnvWithDefaults (line 1955) | func TestParseMultiStringSliceFromEnvWithDefaults(t *testing.T) {
  function TestParseMultiStringSliceFromEnvCascade (line 1971) | func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
  function TestParseMultiStringSliceFromEnvCascadeWithDefaults (line 1987) | func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
  function TestParseMultiStringSliceFromEnvWithDestination (line 2003) | func TestParseMultiStringSliceFromEnvWithDestination(t *testing.T) {
  function TestParseMultiInt (line 2018) | func TestParseMultiInt(t *testing.T) {
  function TestParseDestinationInt (line 2031) | func TestParseDestinationInt(t *testing.T) {
  function TestParseMultiIntFromEnv (line 2047) | func TestParseMultiIntFromEnv(t *testing.T) {
  function TestParseMultiIntFromEnvCascade (line 2061) | func TestParseMultiIntFromEnvCascade(t *testing.T) {
  function TestParseMultiIntSlice (line 2075) | func TestParseMultiIntSlice(t *testing.T) {
  function TestParseMultiIntSliceWithDefaults (line 2091) | func TestParseMultiIntSliceWithDefaults(t *testing.T) {
  function TestParseMultiIntSliceWithDefaultsUnset (line 2107) | func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
  function TestParseMultiIntSliceFromEnv (line 2121) | func TestParseMultiIntSliceFromEnv(t *testing.T) {
  function TestParseMultiIntSliceFromEnvWithDefaults (line 2139) | func TestParseMultiIntSliceFromEnvWithDefaults(t *testing.T) {
  function TestParseMultiIntSliceFromEnvCascade (line 2156) | func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
  function TestParseMultiFloat64 (line 2174) | func TestParseMultiFloat64(t *testing.T) {
  function TestParseDestinationFloat64 (line 2187) | func TestParseDestinationFloat64(t *testing.T) {
  function TestParseMultiFloat64FromEnv (line 2203) | func TestParseMultiFloat64FromEnv(t *testing.T) {
  function TestParseMultiFloat64FromEnvCascade (line 2217) | func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
  function TestParseMultiFloat64SliceFromEnv (line 2232) | func TestParseMultiFloat64SliceFromEnv(t *testing.T) {
  function TestParseMultiFloat64SliceFromEnvCascade (line 2246) | func TestParseMultiFloat64SliceFromEnvCascade(t *testing.T) {
  function TestParseMultiBool (line 2260) | func TestParseMultiBool(t *testing.T) {
  function TestParseBoolShortOptionHandle (line 2273) | func TestParseBoolShortOptionHandle(t *testing.T) {
  function TestParseDestinationBool (line 2293) | func TestParseDestinationBool(t *testing.T) {
  function TestParseMultiBoolFromEnv (line 2309) | func TestParseMultiBoolFromEnv(t *testing.T) {
  function TestParseMultiBoolFromEnvCascade (line 2323) | func TestParseMultiBoolFromEnvCascade(t *testing.T) {
  function TestParseBoolFromEnv (line 2337) | func TestParseBoolFromEnv(t *testing.T) {
  function TestParseMultiBoolT (line 2365) | func TestParseMultiBoolT(t *testing.T) {
  function TestStringSlice_Serialized_Set (line 2378) | func TestStringSlice_Serialized_Set(t *testing.T) {
  function TestIntSlice_Serialized_Set (line 2390) | func TestIntSlice_Serialized_Set(t *testing.T) {
  function TestUintSlice_Serialized_Set (line 2402) | func TestUintSlice_Serialized_Set(t *testing.T) {
  function TestUint64Slice_Serialized_Set (line 2414) | func TestUint64Slice_Serialized_Set(t *testing.T) {
  function TestStringMap_Serialized_Set (line 2426) | func TestStringMap_Serialized_Set(t *testing.T) {
  function TestTimestampFlagHelpOutput (line 2448) | func TestTimestampFlagHelpOutput(t *testing.T) {
  function TestTimestamp_set (line 2458) | func TestTimestamp_set(t *testing.T) {
  function TestTimestampFlagApply_SingleFormat (line 2476) | func TestTimestampFlagApply_SingleFormat(t *testing.T) {
  function TestTimestampFlagApply_MultipleFormats (line 2489) | func TestTimestampFlagApply_MultipleFormats(t *testing.T) {
  function TestTimestampFlagApply_ShortenedLayouts (line 2660) | func TestTimestampFlagApply_ShortenedLayouts(t *testing.T) {
  function TestTimestampFlagApplyValue (line 2700) | func TestTimestampFlagApplyValue(t *testing.T) {
  function TestTimestampFlagApply_Fail_Parse_Wrong_Layout (line 2713) | func TestTimestampFlagApply_Fail_Parse_Wrong_Layout(t *testing.T) {
  function TestTimestampFlagApply_Fail_Parse_Wrong_Time (line 2725) | func TestTimestampFlagApply_Fail_Parse_Wrong_Time(t *testing.T) {
  function TestTimestampFlagApply_Timezoned (line 2736) | func TestTimestampFlagApply_Timezoned(t *testing.T) {
  function TestTimestampFlagValueFromCommand (line 2750) | func TestTimestampFlagValueFromCommand(t *testing.T) {
  type flagDefaultTestCase (line 2764) | type flagDefaultTestCase struct
  function TestFlagDefaultValue (line 2771) | func TestFlagDefaultValue(t *testing.T) {
  type flagDefaultTestCaseWithEnv (line 2853) | type flagDefaultTestCaseWithEnv struct
  function TestFlagDefaultValueWithEnv (line 2861) | func TestFlagDefaultValueWithEnv(t *testing.T) {
  type flagValueTestCase (line 3017) | type flagValueTestCase struct
  function TestFlagValue (line 3024) | func TestFlagValue(t *testing.T) {
  function TestTimestampFlagApply_WithDestination (line 3084) | func TestTimestampFlagApply_WithDestination(t *testing.T) {
  function TestSliceShortOptionHandle (line 3100) | func TestSliceShortOptionHandle(t *testing.T) {
  function TestCustomizedSliceFlagSeparator (line 3137) | func TestCustomizedSliceFlagSeparator(t *testing.T) {
  function TestFlagSplitMultiValues_Disabled (line 3146) | func TestFlagSplitMultiValues_Disabled(t *testing.T) {
  function TestStringMapFlagHelpOutput (line 3166) | func TestStringMapFlagHelpOutput(t *testing.T) {
  function TestStringMapFlagWithEnvVarHelpOutput (line 3173) | func TestStringMapFlagWithEnvVarHelpOutput(t *testing.T) {
  function TestStringMapFlagApply_SetsAllNames (line 3187) | func TestStringMapFlagApply_SetsAllNames(t *testing.T) {
  function TestStringMapFlagApply_UsesEnvValues_noDefault (line 3198) | func TestStringMapFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  function TestStringMapFlagApply_UsesEnvValues_withDefault (line 3213) | func TestStringMapFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  function TestStringMapFlagApply_DefaultValueWithDestination (line 3228) | func TestStringMapFlagApply_DefaultValueWithDestination(t *testing.T) {
  function TestStringMapFlagValueFromCommand (line 3242) | func TestStringMapFlagValueFromCommand(t *testing.T) {
  function TestStringMapFlagApply_Error (line 3256) | func TestStringMapFlagApply_Error(t *testing.T) {
  function TestZeroValueMutexFlag (line 3267) | func TestZeroValueMutexFlag(t *testing.T) {
  function TestMutexFlagCategory (line 3272) | func TestMutexFlagCategory(t *testing.T) {
  function TestExtFlag (line 3292) | func TestExtFlag(t *testing.T) {
  function TestSliceValuesNil (line 3317) | func TestSliceValuesNil(t *testing.T) {
  function TestFileHint (line 3333) | func TestFileHint(t *testing.T) {
  function TestHasFlags (line 3340) | func TestHasFlags(t *testing.T) {
  function TestFlagsByName (line 3351) | func TestFlagsByName(t *testing.T) {
  function TestNonStringMap (line 3378) | func TestNonStringMap(t *testing.T) {
  function TestUnquoteUsage (line 3399) | func TestUnquoteUsage(t *testing.T) {
  function TestEnvHintWindows (line 3421) | func TestEnvHintWindows(t *testing.T) {
  function TestDocGetValue (line 3427) | func TestDocGetValue(t *testing.T) {
  function TestGenericFlag_SatisfiesFlagInterface (line 3434) | func TestGenericFlag_SatisfiesFlagInterface(t *testing.T) {
  function TestGenericValue_SatisfiesBoolInterface (line 3441) | func TestGenericValue_SatisfiesBoolInterface(t *testing.T) {
  function TestGenericFlag_SatisfiesFmtStringerInterface (line 3460) | func TestGenericFlag_SatisfiesFmtStringerInterface(t *testing.T) {
  function TestGenericFlag_SatisfiesRequiredFlagInterface (line 3466) | func TestGenericFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
  function TestGenericFlag_SatisfiesVisibleFlagInterface (line 3472) | func TestGenericFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
  function TestGenericFlag_SatisfiesDocFlagInterface (line 3478) | func TestGenericFlag_SatisfiesDocFlagInterface(t *testing.T) {
  function TestGenericValue (line 3484) | func TestGenericValue(t *testing.T) {
  function TestEndValue (line 3491) | func TestEndValue(t *testing.T) {

FILE: flag_timestamp.go
  type TimestampConfig (line 12) | type TimestampConfig struct
  type timestampValue (line 23) | type timestampValue struct
    method Create (line 34) | func (t timestampValue) Create(val time.Time, p *time.Time, c Timestam...
    method ToString (line 43) | func (t timestampValue) ToString(b time.Time) string {
    method Set (line 54) | func (t *timestampValue) Set(value string) error {
    method String (line 125) | func (t *timestampValue) String() string {
    method Get (line 130) | func (t *timestampValue) Get() any {
  method Timestamp (line 135) | func (cmd *Command) Timestamp(name string) time.Time {

FILE: flag_uint.go
  type uintValue (line 17) | type uintValue struct
  method Create (line 24) | func (i uintValue[T]) Create(val T, p *T, c IntegerConfig) Value {
  method ToString (line 33) | func (i uintValue[T]) ToString(b T) string {
  method Set (line 40) | func (i *uintValue[T]) Set(s string) error {
  method Get (line 49) | func (i *uintValue[T]) Get() any { return *i.val }
  method String (line 51) | func (i *uintValue[T]) String() string {
  method Uint (line 62) | func (cmd *Command) Uint(name string) uint {
  method Uint8 (line 68) | func (cmd *Command) Uint8(name string) uint8 {
  method Uint16 (line 74) | func (cmd *Command) Uint16(name string) uint16 {
  method Uint32 (line 80) | func (cmd *Command) Uint32(name string) uint32 {
  method Uint64 (line 86) | func (cmd *Command) Uint64(name string) uint64 {
  function getUint (line 90) | func getUint[T uint | uint8 | uint16 | uint32 | uint64](cmd *Command, na...

FILE: flag_uint_slice.go
  method UintSlice (line 26) | func (cmd *Command) UintSlice(name string) []uint {
  method Uint8Slice (line 32) | func (cmd *Command) Uint8Slice(name string) []uint8 {
  method Uint16Slice (line 38) | func (cmd *Command) Uint16Slice(name string) []uint16 {
  method Uint32Slice (line 44) | func (cmd *Command) Uint32Slice(name string) []uint32 {
  method Uint64Slice (line 50) | func (cmd *Command) Uint64Slice(name string) []uint64 {
  function getUintSlice (line 54) | func getUintSlice[T uint | uint8 | uint16 | uint32 | uint64](cmd *Comman...

FILE: flag_uint_slice_test.go
  function TestCommand_UintSlice (line 11) | func TestCommand_UintSlice(t *testing.T) {
  function TestCommand_Uint8Slice (line 60) | func TestCommand_Uint8Slice(t *testing.T) {
  function TestCommand_Uint16Slice (line 109) | func TestCommand_Uint16Slice(t *testing.T) {
  function TestCommand_Uint32Slice (line 158) | func TestCommand_Uint32Slice(t *testing.T) {
  function TestCommand_Uint64Slice (line 207) | func TestCommand_Uint64Slice(t *testing.T) {

FILE: flag_uint_test.go
  function TestUintFlag (line 12) | func TestUintFlag(t *testing.T) {
  function TestUint8Flag (line 65) | func TestUint8Flag(t *testing.T) {
  function TestUint16Flag (line 118) | func TestUint16Flag(t *testing.T) {
  function TestUint32Flag (line 179) | func TestUint32Flag(t *testing.T) {
  function TestUint64Flag (line 240) | func TestUint64Flag(t *testing.T) {
  function TestUintFlagExt (line 293) | func TestUintFlagExt(t *testing.T) {

FILE: flag_validation_test.go
  function TestFlagDefaultValidation (line 10) | func TestFlagDefaultValidation(t *testing.T) {
  function TestBoolInverseFlagDefaultValidation (line 39) | func TestBoolInverseFlagDefaultValidation(t *testing.T) {
  function TestFlagValidation (line 64) | func TestFlagValidation(t *testing.T) {
  function TestBoolInverseFlagValidation (line 144) | func TestBoolInverseFlagValidation(t *testing.T) {

FILE: funcs.go
  type ShellCompleteFunc (line 6) | type ShellCompleteFunc
  type BeforeFunc (line 11) | type BeforeFunc
  type AfterFunc (line 15) | type AfterFunc
  type ActionFunc (line 18) | type ActionFunc
  type CommandNotFoundFunc (line 21) | type CommandNotFoundFunc
  type ConfigureShellCompletionCommand (line 24) | type ConfigureShellCompletionCommand
  type OnUsageErrorFunc (line 30) | type OnUsageErrorFunc
  type InvalidFlagAccessFunc (line 33) | type InvalidFlagAccessFunc
  type ExitErrHandlerFunc (line 37) | type ExitErrHandlerFunc
  type FlagStringFunc (line 41) | type FlagStringFunc
  type FlagNamePrefixFunc (line 45) | type FlagNamePrefixFunc
  type FlagEnvHintFunc (line 49) | type FlagEnvHintFunc
  type FlagFileHintFunc (line 53) | type FlagFileHintFunc

FILE: help.go
  constant helpName (line 15) | helpName  = "help"
  constant helpAlias (line 16) | helpAlias = "h"
  type HelpPrinterFunc (line 20) | type HelpPrinterFunc
  type HelpPrinterCustomFunc (line 23) | type HelpPrinterCustomFunc
  function buildHelpCommand (line 65) | func buildHelpCommand(withAction bool) *Command {
  function helpCommandAction (line 81) | func helpCommandAction(ctx context.Context, cmd *Command) error {
  function ShowRootCommandHelpAndExit (line 145) | func ShowRootCommandHelpAndExit(cmd *Command, exitCode int) {
  function DefaultShowRootCommandHelp (line 154) | func DefaultShowRootCommandHelp(cmd *Command) error {
  function DefaultRootCommandComplete (line 178) | func DefaultRootCommandComplete(ctx context.Context, cmd *Command) {
  function printCommandSuggestions (line 185) | func printCommandSuggestions(commands []*Command, writer io.Writer) {
  function cliArgContains (line 199) | func cliArgContains(flagName string, args []string) bool {
  function printFlagSuggestions (line 216) | func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
  function DefaultCompleteWithFlags (line 252) | func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) {
  function ShowCommandHelpAndExit (line 293) | func ShowCommandHelpAndExit(ctx context.Context, cmd *Command, command s...
  function DefaultShowCommandHelp (line 299) | func DefaultShowCommandHelp(ctx context.Context, cmd *Command, commandNa...
  function ShowSubcommandHelpAndExit (line 345) | func ShowSubcommandHelpAndExit(cmd *Command, exitCode int) {
  function DefaultShowSubcommandHelp (line 351) | func DefaultShowSubcommandHelp(cmd *Command) error {
  function ShowVersion (line 357) | func ShowVersion(cmd *Command) {
  function DefaultPrintVersion (line 363) | func DefaultPrintVersion(cmd *Command) {
  function handleTemplateError (line 367) | func handleTemplateError(err error) {
  function DefaultPrintHelpCustom (line 383) | func DefaultPrintHelpCustom(out io.Writer, templ string, data any, custo...
  function DefaultPrintHelp (line 473) | func DefaultPrintHelp(out io.Writer, templ string, data any) {
  function checkVersion (line 477) | func checkVersion(cmd *Command) bool {
  function checkShellCompleteFlag (line 487) | func checkShellCompleteFlag(c *Command, arguments []string) (bool, []str...
  function checkCompletions (line 511) | func checkCompletions(ctx context.Context, cmd *Command) bool {
  function subtract (line 537) | func subtract(a, b int) int {
  function indent (line 541) | func indent(spaces int, v string) string {
  function nindent (line 546) | func nindent(spaces int, v string) string {
  function wrap (line 550) | func wrap(input string, offset int, wrapAt int) string {
  function wrapLine (line 574) | func wrapLine(input string, offset int, wrapAt int, padding string) stri...
  function offset (line 600) | func offset(input string, fixed int) int {
  function offsetCommands (line 618) | func offsetCommands(cmds []*Command, fixed int) int {

FILE: help_test.go
  function Test_ShowRootCommandHelp_NoAuthor (line 18) | func Test_ShowRootCommandHelp_NoAuthor(t *testing.T) {
  function Test_ShowRootCommandHelp_NoVersion (line 28) | func Test_ShowRootCommandHelp_NoVersion(t *testing.T) {
  function Test_ShowRootCommandHelp_HideVersion (line 41) | func Test_ShowRootCommandHelp_HideVersion(t *testing.T) {
  function Test_ShowRootCommandHelp_MultiLineDescription (line 54) | func Test_ShowRootCommandHelp_MultiLineDescription(t *testing.T) {
  function TestShowCommandHelpAndExit (line 68) | func TestShowCommandHelpAndExit(t *testing.T) {
  function TestShowRootCommandHelpAndExit (line 85) | func TestShowRootCommandHelpAndExit(t *testing.T) {
  function TestShowSubcommandHelpAndExit (line 94) | func TestShowSubcommandHelpAndExit(t *testing.T) {
  function Test_HelpFlag_RequiredFlagsNoDefault (line 111) | func Test_HelpFlag_RequiredFlagsNoDefault(t *testing.T) {
  function Test_HelpCommand_RequiredFlagsNoDefault (line 139) | func Test_HelpCommand_RequiredFlagsNoDefault(t *testing.T) {
  function Test_Help_Custom_Flags (line 167) | func Test_Help_Custom_Flags(t *testing.T) {
  function Test_Help_Nil_Flags (line 196) | func Test_Help_Nil_Flags(t *testing.T) {
  function Test_Version_Custom_Flags (line 214) | func Test_Version_Custom_Flags(t *testing.T) {
  function Test_helpCommand_Action_ErrorIfNoTopic (line 242) | func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
  function Test_helpCommand_InHelpOutput (line 257) | func Test_helpCommand_InHelpOutput(t *testing.T) {
  function TestHelpCommand_FullName (line 270) | func TestHelpCommand_FullName(t *testing.T) {
  function Test_helpCommand_HideHelpCommand (line 341) | func Test_helpCommand_HideHelpCommand(t *testing.T) {
  function Test_helpCommand_HideHelpFlag (line 355) | func Test_helpCommand_HideHelpFlag(t *testing.T) {
  function Test_helpSubcommand_Action_ErrorIfNoTopic (line 362) | func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
  function TestShowRootCommandHelp_CommandAliases (line 376) | func TestShowRootCommandHelp_CommandAliases(t *testing.T) {
  function TestShowCommandHelp_AppendHelp (line 396) | func TestShowCommandHelp_AppendHelp(t *testing.T) {
  function TestShowCommandHelp_HelpPrinter (line 468) | func TestShowCommandHelp_HelpPrinter(t *testing.T) {
  function TestShowCommandHelp_HelpPrinterCustom (line 546) | func TestShowCommandHelp_HelpPrinterCustom(t *testing.T) {
  function TestShowCommandHelp_CommandAliases (line 626) | func TestShowCommandHelp_CommandAliases(t *testing.T) {
  function TestShowSubcommandHelp_CommandAliases (line 646) | func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
  function TestShowCommandHelp_Customtemplate (line 667) | func TestShowCommandHelp_Customtemplate(t *testing.T) {
  function TestShowSubcommandHelp_CommandUsageText (line 707) | func TestShowSubcommandHelp_CommandUsageText(t *testing.T) {
  function TestShowSubcommandHelp_MultiLine_CommandUsageText (line 726) | func TestShowSubcommandHelp_MultiLine_CommandUsageText(t *testing.T) {
  function TestShowSubcommandHelp_GlobalOptions (line 755) | func TestShowSubcommandHelp_GlobalOptions(t *testing.T) {
  function TestShowSubcommandHelp_GlobalOptions_HideHelpCommand (line 800) | func TestShowSubcommandHelp_GlobalOptions_HideHelpCommand(t *testing.T) {
  function TestShowSubcommandHelp_SubcommandUsageText (line 846) | func TestShowSubcommandHelp_SubcommandUsageText(t *testing.T) {
  function TestShowSubcommandHelp_MultiLine_SubcommandUsageText (line 870) | func TestShowSubcommandHelp_MultiLine_SubcommandUsageText(t *testing.T) {
  function TestShowRootCommandHelp_HiddenCommand (line 904) | func TestShowRootCommandHelp_HiddenCommand(t *testing.T) {
  function TestShowRootCommandHelp_HelpPrinter (line 935) | func TestShowRootCommandHelp_HelpPrinter(t *testing.T) {
  function TestShowRootCommandHelp_HelpPrinterCustom (line 994) | func TestShowRootCommandHelp_HelpPrinterCustom(t *testing.T) {
  function TestShowRootCommandHelp_CustomAppTemplate (line 1053) | func TestShowRootCommandHelp_CustomAppTemplate(t *testing.T) {
  function TestShowRootCommandHelp_UsageText (line 1124) | func TestShowRootCommandHelp_UsageText(t *testing.T) {
  function TestShowRootCommandHelp_MultiLine_UsageText (line 1142) | func TestShowRootCommandHelp_MultiLine_UsageText(t *testing.T) {
  function TestShowRootCommandHelp_CommandMultiLine_UsageText (line 1170) | func TestShowRootCommandHelp_CommandMultiLine_UsageText(t *testing.T) {
  function TestHideHelpCommand (line 1204) | func TestHideHelpCommand(t *testing.T) {
  function TestHideHelpCommand_False (line 1217) | func TestHideHelpCommand_False(t *testing.T) {
  function TestHideHelpCommand_WithHideHelp (line 1230) | func TestHideHelpCommand_WithHideHelp(t *testing.T) {
  function TestHideHelpCommand_WithSubcommands (line 1244) | func TestHideHelpCommand_WithSubcommands(t *testing.T) {
  function TestDefaultCompleteWithFlags (line 1265) | func TestDefaultCompleteWithFlags(t *testing.T) {
  function TestMutuallyExclusiveFlags (line 1458) | func TestMutuallyExclusiveFlags(t *testing.T) {
  function TestWrap (line 1481) | func TestWrap(t *testing.T) {
  function TestWrappedHelp (line 1486) | func TestWrappedHelp(t *testing.T) {
  function TestWrappedCommandHelp (line 1574) | func TestWrappedCommandHelp(t *testing.T) {
  function TestWrappedSubcommandHelp (line 1634) | func TestWrappedSubcommandHelp(t *testing.T) {
  function TestWrappedHelpSubcommand (line 1699) | func TestWrappedHelpSubcommand(t *testing.T) {
  function TestCategorizedHelp (line 1774) | func TestCategorizedHelp(t *testing.T) {
  function Test_checkShellCompleteFlag (line 1858) | func Test_checkShellCompleteFlag(t *testing.T) {
  function TestNIndent (line 1923) | func TestNIndent(t *testing.T) {
  function TestTemplateError (line 1956) | func TestTemplateError(t *testing.T) {
  function TestCliArgContainsFlag (line 1973) | func TestCliArgContainsFlag(t *testing.T) {
  function TestCommandHelpSuggest (line 2026) | func TestCommandHelpSuggest(t *testing.T) {
  function TestWrapLine (line 2042) | func TestWrapLine(t *testing.T) {
  function TestPrintHelpCustomTemplateError (line 2046) | func TestPrintHelpCustomTemplateError(t *testing.T) {
  function TestCustomUsageCommandHelp (line 2087) | func TestCustomUsageCommandHelp(t *testing.T) {

FILE: helpers_test.go
  function init (line 7) | func init() {

FILE: scripts/build.go
  constant badNewsEmoji (line 27) | badNewsEmoji      = "🚨"
  constant goodNewsEmoji (line 28) | goodNewsEmoji     = "✨"
  constant checksPassedEmoji (line 29) | checksPassedEmoji = "✅"
  constant gfmrunVersion (line 31) | gfmrunVersion = "v1.3.0"
  constant v3diffWarning (line 33) | v3diffWarning = `
  function main (line 44) | func main() {
  function sh (line 166) | func sh(ctx context.Context, exe string, args ...string) (string, error) {
  function topRunAction (line 176) | func topRunAction(arg string, args ...string) cli.ActionFunc {
  function runCmd (line 186) | func runCmd(ctx context.Context, arg string, args ...string) error {
  function downloadFile (line 197) | func downloadFile(src, dest string, dirPerm, perm os.FileMode) error {
  function VetActionFunc (line 234) | func VetActionFunc(ctx context.Context, cmd *cli.Command) error {
  function TestActionFunc (line 238) | func TestActionFunc(ctx context.Context, cmd *cli.Command) error {
  function testCleanup (line 270) | func testCleanup(packages []string) error {
  function GfmrunActionFunc (line 295) | func GfmrunActionFunc(ctx context.Context, cmd *cli.Command) error {
  function checkBinarySizeActionFunc (line 409) | func checkBinarySizeActionFunc(ctx context.Context, cmd *cli.Command) (e...
  function GenerateActionFunc (line 491) | func GenerateActionFunc(ctx context.Context, cmd *cli.Command) error {
  function DiffCheckActionFunc (line 506) | func DiffCheckActionFunc(ctx context.Context, cmd *cli.Command) error {
  function EnsureGoimportsActionFunc (line 518) | func EnsureGoimportsActionFunc(ctx context.Context, cmd *cli.Command) er...
  function EnsureGfmrunActionFunc (line 538) | func EnsureGfmrunActionFunc(ctx context.Context, cmd *cli.Command) error {
  function EnsureMkdocsActionFunc (line 563) | func EnsureMkdocsActionFunc(ctx context.Context, cmd *cli.Command) error {
  function SetMkdocsRemoteActionFunc (line 581) | func SetMkdocsRemoteActionFunc(ctx context.Context, cmd *cli.Command) er...
  function LintActionFunc (line 602) | func LintActionFunc(ctx context.Context, cmd *cli.Command) error {
  function V3Diff (line 623) | func V3Diff(ctx context.Context, cmd *cli.Command) error {
  function getSize (line 653) | func getSize(ctx context.Context, sourcePath, builtPath, tags string) (i...

FILE: sort.go
  function lexicographicLess (line 6) | func lexicographicLess(i, j string) bool {

FILE: sort_test.go
  function TestLexicographicLess (line 27) | func TestLexicographicLess(t *testing.T) {

FILE: suggestions.go
  constant suggestDidYouMeanTemplate (line 7) | suggestDidYouMeanTemplate = "Did you mean %q?"
  type SuggestFlagFunc (line 15) | type SuggestFlagFunc
  type SuggestCommandFunc (line 17) | type SuggestCommandFunc
  function jaroDistance (line 24) | func jaroDistance(a, b string) float64 {
  function jaroWinkler (line 82) | func jaroWinkler(a, b string) float64 {
  function suggestFlag (line 105) | func suggestFlag(flags []Flag, provided string, hideHelp bool) string {
  function suggestCommand (line 134) | func suggestCommand(commands []*Command, provided string) (suggestion st...

FILE: suggestions_test.go
  function TestJaroWinkler (line 11) | func TestJaroWinkler(t *testing.T) {
  function TestSuggestFlag (line 38) | func TestSuggestFlag(t *testing.T) {
  function TestSuggestFlagHideHelp (line 59) | func TestSuggestFlagHideHelp(t *testing.T) {
  function TestSuggestFlagFromError (line 70) | func TestSuggestFlagFromError(t *testing.T) {
  function TestSuggestFlagFromErrorWrongError (line 92) | func TestSuggestFlagFromErrorWrongError(t *testing.T) {
  function TestSuggestFlagFromErrorWrongCommand (line 103) | func TestSuggestFlagFromErrorWrongCommand(t *testing.T) {
  function TestSuggestFlagFromErrorNoSuggestion (line 117) | func TestSuggestFlagFromErrorNoSuggestion(t *testing.T) {
  function TestSuggestCommand (line 131) | func TestSuggestCommand(t *testing.T) {

FILE: value_source.go
  type ValueSource (line 11) | type ValueSource interface
  type EnvValueSource (line 22) | type EnvValueSource interface
  type MapSource (line 30) | type MapSource interface
  type ValueSourceChain (line 43) | type ValueSourceChain struct
    method Append (line 53) | func (vsc *ValueSourceChain) Append(other ValueSourceChain) {
    method EnvKeys (line 57) | func (vsc *ValueSourceChain) EnvKeys() []string {
    method String (line 69) | func (vsc *ValueSourceChain) String() string {
    method GoString (line 79) | func (vsc *ValueSourceChain) GoString() string {
    method Lookup (line 89) | func (vsc *ValueSourceChain) Lookup() (string, bool) {
    method LookupWithSource (line 94) | func (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, ...
  function NewValueSourceChain (line 47) | func NewValueSourceChain(src ...ValueSource) ValueSourceChain {
  type envVarValueSource (line 105) | type envVarValueSource struct
    method Lookup (line 109) | func (e *envVarValueSource) Lookup() (string, bool) {
    method IsFromEnv (line 113) | func (e *envVarValueSource) IsFromEnv() bool {
    method Key (line 117) | func (e *envVarValueSource) Key() string {
    method String (line 121) | func (e *envVarValueSource) String() string { return fmt.Sprintf("envi...
    method GoString (line 122) | func (e *envVarValueSource) GoString() string {
  function EnvVar (line 126) | func EnvVar(key string) ValueSource {
  function EnvVars (line 134) | func EnvVars(keys ...string) ValueSourceChain {
  type fileValueSource (line 145) | type fileValueSource struct
    method Lookup (line 149) | func (f *fileValueSource) Lookup() (string, bool) {
    method String (line 154) | func (f *fileValueSource) String() string { return fmt.Sprintf("file %...
    method GoString (line 155) | func (f *fileValueSource) GoString() string {
  function File (line 159) | func File(path string) ValueSource {
  function Files (line 165) | func Files(paths ...string) ValueSourceChain {
  type mapSource (line 175) | type mapSource struct
    method String (line 187) | func (ms *mapSource) String() string { return fmt.Sprintf("map source ...
    method GoString (line 188) | func (ms *mapSource) GoString() string {
    method Lookup (line 195) | func (ms *mapSource) Lookup(name string) (any, bool) {
  function NewMapSource (line 180) | func NewMapSource(name string, m map[any]any) MapSource {
  type mapValueSource (line 231) | type mapValueSource struct
    method String (line 243) | func (mvs *mapValueSource) String() string {
    method GoString (line 247) | func (mvs *mapValueSource) GoString() string {
    method Lookup (line 251) | func (mvs *mapValueSource) Lookup() (string, bool) {
  function NewMapValueSource (line 236) | func NewMapValueSource(key string, ms MapSource) ValueSource {

FILE: value_source_test.go
  function TestZeroValueSourceChain (line 14) | func TestZeroValueSourceChain(t *testing.T) {
  function TestEnvVarValueSource (line 22) | func TestEnvVarValueSource(t *testing.T) {
  function TestEnvVars (line 64) | func TestEnvVars(t *testing.T) {
  function TestFileValueSource (line 76) | func TestFileValueSource(t *testing.T) {
  function TestFilePaths (line 118) | func TestFilePaths(t *testing.T) {
  function TestValueSourceChainEnvKeys (line 133) | func TestValueSourceChainEnvKeys(t *testing.T) {
  function TestValueSourceChain (line 143) | func TestValueSourceChain(t *testing.T) {
  type staticValueSource (line 183) | type staticValueSource struct
    method GoString (line 187) | func (svs *staticValueSource) GoString() string {
    method String (line 190) | func (svs *staticValueSource) String() string         { return svs.v }
    method Lookup (line 191) | func (svs *staticValueSource) Lookup() (string, bool) { return svs.v, ...
  function TestMapValueSource (line 193) | func TestMapValueSource(t *testing.T) {
  function TestMapValueSourceStringer (line 338) | func TestMapValueSourceStringer(t *testing.T) {
Condensed preview — 161 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,022K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 116,
    "preview": "# 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",
    "chars": 217,
    "preview": "---\nname: ask a question\nabout: ask a question - assume stackoverflow's guidelines apply here\ntitle: your question title"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v1-bug-report.md",
    "chars": 2067,
    "preview": "---\nname: v1 bug report\nabout: Create a report to help us fix v1 bugs\ntitle: 'your bug title goes here'\nlabels: 'kind/bu"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v2-bug-report.md",
    "chars": 1961,
    "preview": "---\nname: v2 bug report\nabout: Create a report to help us fix v2 bugs\ntitle: 'your bug title goes here'\nlabels: 'kind/bu"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v3-bug-report.md",
    "chars": 1961,
    "preview": "---\nname: v3 bug report\nabout: Create a report to help us fix v3 bugs\ntitle: 'your bug title goes here'\nlabels: 'kind/bu"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/v3-feature-request.md",
    "chars": 1306,
    "preview": "---\nname: v3 feature request\nabout: Suggest an improvement to go into v3\ntitle: 'your feature title goes here'\nlabels: '"
  },
  {
    "path": ".github/codecov.yml",
    "chars": 166,
    "preview": "comment: false\ncoverage:\n  status:\n    project:\n      default:\n        threshold: 5%\n    patch:\n      default:\n        t"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 335,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: gomod\n    directory: /\n    schedule:\n      interval: weekly\n  - package-ecosy"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1606,
    "preview": "<!--\n  This template provides some ideas of things to include in your PR description.\n  To start, try providing a short "
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 502,
    "preview": "name: Run lints\n\non:\n  push:\n    tags:\n      - v3.*\n    branches:\n      - main\n  pull_request:\n    branches:\n      - mai"
  },
  {
    "path": ".github/workflows/publish-docs.yml",
    "chars": 1252,
    "preview": "name: publish docs\n\non:\n  push:\n    branches:\n      - main\n    tags:\n      - v3.*\n\npermissions:\n  contents: read\n\njobs:\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 1332,
    "preview": "name: Run tests\n\non:\n  push:\n    branches:\n      - main\n    tags:\n      - v3.*\n  pull_request:\n    branches:\n      - mai"
  },
  {
    "path": ".gitignore",
    "chars": 110,
    "preview": "*.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",
    "chars": 154,
    "preview": "version: \"2\"\n\nformatters:\n  enable:\n    - gofumpt\n\nlinters:\n  enable:\n    - makezero\n    - misspell\n  exclusions:\n    pr"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3268,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "LICENSE",
    "chars": 1079,
    "preview": "MIT License\n\nCopyright (c) 2023 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "Makefile",
    "chars": 819,
    "preview": "# NOTE: this Makefile is meant to provide a simplified entry point for humans to\n# run all of the critical steps to veri"
  },
  {
    "path": "README.md",
    "chars": 2380,
    "preview": "# Welcome to urfave/cli\n\n[![Go Reference][goreference_badge]][goreference_link]\n[![Go Report Card][goreportcard_badge]]["
  },
  {
    "path": "args.go",
    "chars": 10589,
    "preview": "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\t"
  },
  {
    "path": "args_test.go",
    "chars": 13565,
    "preview": "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 *tes"
  },
  {
    "path": "autocomplete/bash_autocomplete",
    "chars": 1074,
    "preview": "#!/bin/bash\n\n# This is a shell completion script auto-generated by https://github.com/urfave/cli for bash.\n\n# Macs have "
  },
  {
    "path": "autocomplete/fish_autocomplete",
    "chars": 1058,
    "preview": "# This is a shell completion script auto-generated by https://github.com/urfave/cli for fish.\n\nfunction __%[1]_perform_c"
  },
  {
    "path": "autocomplete/powershell_autocomplete.ps1",
    "chars": 428,
    "preview": "$fn = $($MyInvocation.MyCommand.Name)\n$name = $fn -replace \"(.*)\\.ps1$\", '$1'\nRegister-ArgumentCompleter -Native -Comman"
  },
  {
    "path": "autocomplete/zsh_autocomplete",
    "chars": 858,
    "preview": "#compdef %[1]s\ncompdef _%[1]s %[1]s\n\n# This is a shell completion script auto-generated by https://github.com/urfave/cli"
  },
  {
    "path": "category.go",
    "chars": 4403,
    "preview": "package cli\n\nimport \"sort\"\n\n// CommandCategories interface allows for category manipulation\ntype CommandCategories inter"
  },
  {
    "path": "cli.go",
    "chars": 1192,
    "preview": "// Package cli provides a minimal framework for creating and organizing command line\n// Go applications. cli is designed"
  },
  {
    "path": "cli_test.go",
    "chars": 1216,
    "preview": "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/s"
  },
  {
    "path": "command.go",
    "chars": 17720,
    "preview": "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 fla"
  },
  {
    "path": "command_parse.go",
    "chars": 6481,
    "preview": "package cli\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"unicode\"\n)\n\nconst (\n\tprovidedButNotDefinedErrMsg = \"flag provided but not defi"
  },
  {
    "path": "command_run.go",
    "chars": 10117,
    "preview": "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() "
  },
  {
    "path": "command_setup.go",
    "chars": 5786,
    "preview": "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 []st"
  },
  {
    "path": "command_stop_on_nth_arg_test.go",
    "chars": 9199,
    "preview": "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"
  },
  {
    "path": "command_test.go",
    "chars": 133814,
    "preview": "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\"st"
  },
  {
    "path": "completion.go",
    "chars": 2733,
    "preview": "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/"
  },
  {
    "path": "completion_test.go",
    "chars": 5532,
    "preview": "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"
  },
  {
    "path": "docs/CHANGELOG.md",
    "chars": 30608,
    "preview": "> :warning: This document is no longer being actively maintained. Please see the\n> [releases page](https://github.com/ur"
  },
  {
    "path": "docs/CNAME",
    "chars": 15,
    "preview": "cli.urfave.org\n"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "chars": 4821,
    "preview": "## Contributing\n\nWelcome to the `urfave/cli` contributor docs! This goal of this document is to help those\ninterested in"
  },
  {
    "path": "docs/RELEASING.md",
    "chars": 2680,
    "preview": "# Releasing urfave/cli\n\nReleasing small batches often is [backed by\nresearch](https://itrevolution.com/accelerate-book/)"
  },
  {
    "path": "docs/SECURITY.md",
    "chars": 934,
    "preview": "# Security Policy\n\nHello and thank you for your interest in the `urfave/cli` security\npolicy! :tada: :lock:\n\n## Supporte"
  },
  {
    "path": "docs/go.mod",
    "chars": 321,
    "preview": "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/c"
  },
  {
    "path": "docs/go.sum",
    "chars": 1781,
    "preview": "github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=\ngithub.com/BurntSushi/toml v1.3.2/go.m"
  },
  {
    "path": "docs/index.md",
    "chars": 3805,
    "preview": "<!--\nNOTE: This first section is intentionally identical to the top-level README.md at\nhttps://github.com/urfave/cli/blo"
  },
  {
    "path": "docs/migrate-v1-to-v2.md",
    "chars": 5056,
    "preview": "# Migration Guide: v1 to v2\n\nv2 has a number of breaking changes but converting is relatively\nstraightforward: make the "
  },
  {
    "path": "docs/migrate-v2-to-v3.md",
    "chars": 7641,
    "preview": "# Migration Guide: v2 to v3\n\nv3 has a number of breaking changes but converting is relatively\nstraightforward: make the "
  },
  {
    "path": "docs/package.go",
    "chars": 231,
    "preview": "// Package docs is an empty shell! This file is *only* meant to capture the dependencies\n// required by the `gfmrun` doc"
  },
  {
    "path": "docs/v1/examples/arguments.md",
    "chars": 440,
    "preview": "---\ntags:\n  - v1\n---\n\nYou can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:\n\n<!-- {\n  \"output\""
  },
  {
    "path": "docs/v1/examples/bash-completions.md",
    "chars": 2641,
    "preview": "---\ntags:\n  - v1\n---\n\nYou can enable completion commands by setting the `EnableBashCompletion`\nflag on the `App` object."
  },
  {
    "path": "docs/v1/examples/combining-short-options.md",
    "chars": 1766,
    "preview": "---\ntags:\n  - v1\n---\n\nTraditional use of options using their shortnames look like this:\n\n```\n$ cmd -s -o -m \"Some messag"
  },
  {
    "path": "docs/v1/examples/exit-codes.md",
    "chars": 895,
    "preview": "---\ntags:\n  - v1\n---\n\nCalling `App.Run` will not automatically call `os.Exit`, which means that by\ndefault the exit code"
  },
  {
    "path": "docs/v1/examples/flags.md",
    "chars": 8687,
    "preview": "---\ntags:\n  - v1\n---\n\nSetting and querying flags is simple.\n\n<!-- {\n  \"output\": \"Hello Nefertiti\"\n} -->\n``` go\npackage m"
  },
  {
    "path": "docs/v1/examples/generated-help-text.md",
    "chars": 2317,
    "preview": "---\ntags:\n  - v1\n---\n\nThe default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked\nby the cli interna"
  },
  {
    "path": "docs/v1/examples/greet.md",
    "chars": 1151,
    "preview": "---\ntags:\n  - v1\n---\n\nBeing a programmer can be a lonely job. Thankfully by the power of automation\nthat is not the case"
  },
  {
    "path": "docs/v1/examples/subcommands-categories.md",
    "chars": 664,
    "preview": "---\ntags:\n  - v1\n---\n\nFor additional organization in apps that have many subcommands, you can\nassociate a category for e"
  },
  {
    "path": "docs/v1/examples/subcommands.md",
    "chars": 1525,
    "preview": "---\ntags:\n  - v1\n---\n\nSubcommands can be defined for a more git-like command line app.\n\n<!-- {\n  \"args\": [\"template\", \"a"
  },
  {
    "path": "docs/v1/examples/version-flag.md",
    "chars": 9511,
    "preview": "---\ntags:\n  - v1\n---\n\nThe default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which\nis checked by the"
  },
  {
    "path": "docs/v1/getting-started.md",
    "chars": 1076,
    "preview": "---\ntags:\n  - v1\n---\n\nOne of the philosophies behind cli is that an API should be playful and full of\ndiscovery. So a cl"
  },
  {
    "path": "docs/v1/migrating-to-v2.md",
    "chars": 247,
    "preview": "---\ntags:\n  - v1\n---\n\nThere are a small set of breaking changes between v1 and v2.\nConverting is relatively straightforw"
  },
  {
    "path": "docs/v2/examples/arguments.md",
    "chars": 450,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nYou can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:"
  },
  {
    "path": "docs/v2/examples/bash-completions.md",
    "chars": 6100,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nYou can enable completion commands by setting the `EnableBashCompletion` flag o"
  },
  {
    "path": "docs/v2/examples/combining-short-options.md",
    "chars": 1833,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nTraditional use of options using their shortnames look like this:\n\n```sh-sessio"
  },
  {
    "path": "docs/v2/examples/exit-codes.md",
    "chars": 868,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nCalling `App.Run` will not automatically call `os.Exit`, which means that by\nde"
  },
  {
    "path": "docs/v2/examples/flags.md",
    "chars": 13028,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nSetting and querying flags is simple.\n\n<!-- {\n  \"output\": \"Hello Nefertiti\"\n} -"
  },
  {
    "path": "docs/v2/examples/full-api-example.md",
    "chars": 7146,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\n**Notice**: This is a contrived (functioning) example meant strictly for API\nde"
  },
  {
    "path": "docs/v2/examples/generated-help-text.md",
    "chars": 2246,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nThe default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked"
  },
  {
    "path": "docs/v2/examples/greet.md",
    "chars": 1160,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nBeing a programmer can be a lonely job. Thankfully by the power of automation\nt"
  },
  {
    "path": "docs/v2/examples/subcommands-categories.md",
    "chars": 641,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nFor additional organization in apps that have many subcommands, you can\nassocia"
  },
  {
    "path": "docs/v2/examples/subcommands.md",
    "chars": 1432,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nSubcommands can be defined for a more git-like command line app.\n\n<!-- {\n  \"arg"
  },
  {
    "path": "docs/v2/examples/suggestions.md",
    "chars": 281,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nTo enable flag and command suggestions, set `app.Suggest = true`. If the sugges"
  },
  {
    "path": "docs/v2/examples/timestamp-flag.md",
    "chars": 1271,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nUsing the timestamp flag is simple. Please refer to\n[`time.Parse`](https://gola"
  },
  {
    "path": "docs/v2/examples/version-flag.md",
    "chars": 1272,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nThe default version flag (`-v/--version`) is defined as `cli.VersionFlag`, whic"
  },
  {
    "path": "docs/v2/getting-started.md",
    "chars": 1321,
    "preview": "---\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"
  },
  {
    "path": "docs/v2/migrating-from-older-releases.md",
    "chars": 369,
    "preview": "---\ntags:\n  - v2\nsearch:\n  boost: 2\n---\n\nThere are a small set of breaking changes between v1 and v2.  Converting is\nrel"
  },
  {
    "path": "docs/v2/migrating-to-v3.md",
    "chars": 247,
    "preview": "---\ntags:\n  - v2\n---\n\nThere are a small set of breaking changes between v2 and v3.\nConverting is relatively straightforw"
  },
  {
    "path": "docs/v3/examples/arguments/advanced.md",
    "chars": 4189,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThe [Basics] showed how to access arguments for a command. They are all retriev"
  },
  {
    "path": "docs/v3/examples/arguments/basics.md",
    "chars": 1696,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nLets add some arguments to our greeter app. This allows you to change the behav"
  },
  {
    "path": "docs/v3/examples/completions/customizations.md",
    "chars": 2721,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nIf default completion isn't sufficient additional customizations are available "
  },
  {
    "path": "docs/v3/examples/completions/shell-completions.md",
    "chars": 5301,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThe urfave/cli v3 library supports programmable completion for apps utilizing i"
  },
  {
    "path": "docs/v3/examples/exit-codes.md",
    "chars": 931,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nCalling `Command.Run` will not automatically call `os.Exit`, which means that b"
  },
  {
    "path": "docs/v3/examples/flags/advanced.md",
    "chars": 10383,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\n#### Alternate Names\n\nYou can set alternate (or short) names for flags by provi"
  },
  {
    "path": "docs/v3/examples/flags/basics.md",
    "chars": 6221,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nFlags, also called options, can be used to control various behaviour of the app"
  },
  {
    "path": "docs/v3/examples/flags/short-options.md",
    "chars": 1887,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nTraditional use of options using their shortnames look like this:\n\n```sh-sessio"
  },
  {
    "path": "docs/v3/examples/flags/value-sources.md",
    "chars": 4459,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nFlags can have their default values set from different sources. The following s"
  },
  {
    "path": "docs/v3/examples/full-api-example.md",
    "chars": 6471,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\n**Notice**: This is a contrived (functioning) example meant strictly for API\nde"
  },
  {
    "path": "docs/v3/examples/greet.md",
    "chars": 1419,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nBeing a programmer can be a lonely job. Thankfully by the power of automation\nt"
  },
  {
    "path": "docs/v3/examples/help/generated-help-text.md",
    "chars": 2354,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThe default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked"
  },
  {
    "path": "docs/v3/examples/help/suggestions.md",
    "chars": 285,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nTo enable flag and command suggestions, set `Command.Suggest = true`. If the su"
  },
  {
    "path": "docs/v3/examples/subcommands/basics.md",
    "chars": 1542,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nSubcommands can be defined for a more git-like command line app.\n\n<!-- {\n  \"arg"
  },
  {
    "path": "docs/v3/examples/subcommands/categories.md",
    "chars": 670,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nFor additional organization in apps that have many subcommands, you can\nassocia"
  },
  {
    "path": "docs/v3/getting-started.md",
    "chars": 1350,
    "preview": "---\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"
  },
  {
    "path": "docs/v3/index.md",
    "chars": 11,
    "preview": "# v3 guide\n"
  },
  {
    "path": "docs/v3/migrating-from-older-releases.md",
    "chars": 369,
    "preview": "---\ntags:\n  - v3\nsearch:\n  boost: 2\n---\n\nThere are a small set of breaking changes between v1 and v3.  Converting is\nrel"
  },
  {
    "path": "docs.go",
    "chars": 2902,
    "preview": "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) "
  },
  {
    "path": "errors.go",
    "chars": 4399,
    "preview": "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 d"
  },
  {
    "path": "errors_test.go",
    "chars": 4775,
    "preview": "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 TestHandleExit"
  },
  {
    "path": "examples/example-cli/example-cli.go",
    "chars": 198,
    "preview": "// 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\n"
  },
  {
    "path": "examples/example-hello-world/example-hello-world.go",
    "chars": 126,
    "preview": "// example hello world used for binary size checking\n\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"hello worl"
  },
  {
    "path": "examples_test.go",
    "chars": 15298,
    "preview": "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 example"
  },
  {
    "path": "fish.go",
    "chars": 5020,
    "preview": "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"
  },
  {
    "path": "fish_test.go",
    "chars": 1783,
    "preview": "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/"
  },
  {
    "path": "flag.go",
    "chars": 6033,
    "preview": "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\tdef"
  },
  {
    "path": "flag_bool.go",
    "chars": 1649,
    "preview": "package cli\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\ntype BoolFlag = FlagBase[bool, BoolConfig, boolValue]\n\n// BoolConfig defin"
  },
  {
    "path": "flag_bool_with_inverse.go",
    "chars": 7682,
    "preview": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n)\n\nvar DefaultInverseBoolPrefix = \"no-\"\n\ntype BoolWithInver"
  },
  {
    "path": "flag_bool_with_inverse_test.go",
    "chars": 10185,
    "preview": "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 errBothEnvF"
  },
  {
    "path": "flag_duration.go",
    "chars": 1147,
    "preview": "package cli\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype DurationFlag = FlagBase[time.Duration, NoConfig, durationValue]\n\n// -- time"
  },
  {
    "path": "flag_ext.go",
    "chars": 926,
    "preview": "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"
  },
  {
    "path": "flag_float.go",
    "chars": 1798,
    "preview": "package cli\n\nimport (\n\t\"strconv\"\n\t\"unsafe\"\n)\n\ntype (\n\tFloatFlag   = FlagBase[float64, NoConfig, floatValue[float64]]\n\tFl"
  },
  {
    "path": "flag_float_slice.go",
    "chars": 1225,
    "preview": "package cli\n\ntype (\n\tFloatSlice       = SliceBase[float64, NoConfig, floatValue[float64]]\n\tFloat32Slice     = SliceBase["
  },
  {
    "path": "flag_float_slice_test.go",
    "chars": 3112,
    "preview": "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\n"
  },
  {
    "path": "flag_float_test.go",
    "chars": 3274,
    "preview": "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\n"
  },
  {
    "path": "flag_generic.go",
    "chars": 1277,
    "preview": "package cli\n\ntype GenericFlag = FlagBase[Value, NoConfig, genericValue]\n\n// -- Value Value\ntype genericValue struct {\n\tv"
  },
  {
    "path": "flag_impl.go",
    "chars": 10575,
    "preview": "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// "
  },
  {
    "path": "flag_int.go",
    "chars": 2356,
    "preview": "package cli\n\nimport (\n\t\"strconv\"\n\t\"unsafe\"\n)\n\ntype (\n\tIntFlag   = FlagBase[int, IntegerConfig, intValue[int]]\n\tInt8Flag "
  },
  {
    "path": "flag_int_slice.go",
    "chars": 1923,
    "preview": "package cli\n\ntype (\n\tIntSlice       = SliceBase[int, IntegerConfig, intValue[int]]\n\tInt8Slice      = SliceBase[int8, Int"
  },
  {
    "path": "flag_int_slice_test.go",
    "chars": 5020,
    "preview": "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\n"
  },
  {
    "path": "flag_int_test.go",
    "chars": 7323,
    "preview": "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/requ"
  },
  {
    "path": "flag_map_impl.go",
    "chars": 3480,
    "preview": "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 "
  },
  {
    "path": "flag_mutex.go",
    "chars": 1106,
    "preview": "package cli\n\n// MutuallyExclusiveFlags defines a mutually exclusive flag group\n// Multiple option paths can be provided "
  },
  {
    "path": "flag_mutex_test.go",
    "chars": 2226,
    "preview": "package cli\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc newCommand() *Command {\n\tretu"
  },
  {
    "path": "flag_number_slice.go",
    "chars": 436,
    "preview": "package cli\n\ntype numberType interface {\n\tint | int8 | int16 | int32 | int64 | float32 | float64\n}\n\nfunc getNumberSlice["
  },
  {
    "path": "flag_number_slice_test.go",
    "chars": 841,
    "preview": "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\n"
  },
  {
    "path": "flag_slice_base.go",
    "chars": 3032,
    "preview": "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"
  },
  {
    "path": "flag_string.go",
    "chars": 1364,
    "preview": "package cli\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype StringFlag = FlagBase[string, StringConfig, stringValue]\n\n// StringConfi"
  },
  {
    "path": "flag_string_map.go",
    "chars": 637,
    "preview": "package cli\n\ntype (\n\tStringMap     = MapBase[string, StringConfig, stringValue]\n\tStringMapFlag = FlagBase[map[string]str"
  },
  {
    "path": "flag_string_slice.go",
    "chars": 632,
    "preview": "package cli\n\ntype (\n\tStringSlice     = SliceBase[string, StringConfig, stringValue]\n\tStringSliceFlag = FlagBase[[]string"
  },
  {
    "path": "flag_test.go",
    "chars": 100071,
    "preview": "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\"tes"
  },
  {
    "path": "flag_timestamp.go",
    "chars": 3204,
    "preview": "package cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n)\n\ntype TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampVal"
  },
  {
    "path": "flag_uint.go",
    "chars": 2324,
    "preview": "package cli\n\nimport (\n\t\"strconv\"\n\t\"unsafe\"\n)\n\ntype (\n\tUintFlag   = FlagBase[uint, IntegerConfig, uintValue[uint]]\n\tUint8"
  },
  {
    "path": "flag_uint_slice.go",
    "chars": 2344,
    "preview": "package cli\n\ntype (\n\tUintSlice       = SliceBase[uint, IntegerConfig, uintValue[uint]]\n\tUint8Slice      = SliceBase[uint"
  },
  {
    "path": "flag_uint_slice_test.go",
    "chars": 5060,
    "preview": "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\n"
  },
  {
    "path": "flag_uint_test.go",
    "chars": 7068,
    "preview": "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/requ"
  },
  {
    "path": "flag_validation_test.go",
    "chars": 3113,
    "preview": "package cli\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFlagDefaultValidation(t *tes"
  },
  {
    "path": "funcs.go",
    "chars": 2440,
    "preview": "package cli\n\nimport \"context\"\n\n// ShellCompleteFunc is an action to execute when the shell completion flag is set\ntype S"
  },
  {
    "path": "go.mod",
    "chars": 233,
    "preview": "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-"
  },
  {
    "path": "go.sum",
    "chars": 883,
    "preview": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.m"
  },
  {
    "path": "godoc-current.txt",
    "chars": 57048,
    "preview": "package cli // import \"github.com/urfave/cli/v3\"\n\nPackage cli provides a minimal framework for creating and organizing c"
  },
  {
    "path": "help.go",
    "chars": 17538,
    "preview": "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\ncon"
  },
  {
    "path": "help_test.go",
    "chars": 48632,
    "preview": "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/st"
  },
  {
    "path": "helpers_test.go",
    "chars": 91,
    "preview": "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",
    "chars": 127,
    "preview": "mkdocs-git-revision-date-localized-plugin==1.5.1\nmkdocs-material==9.7.4\nmkdocs==1.6.1\nmkdocs-redirects==1.2.2\npygments=="
  },
  {
    "path": "mkdocs.yml",
    "chars": 4953,
    "preview": "# NOTE: the mkdocs dependencies will need to be installed out of\n# band until this whole thing gets more automated:\n#\n# "
  },
  {
    "path": "scripts/build.go",
    "chars": 15856,
    "preview": "// local build script file, similar to a makefile or collection of bash scripts in other projects\n\npackage main\n\nimport "
  },
  {
    "path": "sort.go",
    "chars": 520,
    "preview": "package cli\n\nimport \"unicode\"\n\n// lexicographicLess compares strings alphabetically considering case.\nfunc lexicographic"
  },
  {
    "path": "sort_test.go",
    "chars": 565,
    "preview": "package cli\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar lexicographicLessTests = []struct {\n\ti   "
  },
  {
    "path": "staticcheck.conf",
    "chars": 15,
    "preview": "checks=[\"all\"]\n"
  },
  {
    "path": "suggestions.go",
    "chars": 3437,
    "preview": "package cli\n\nimport (\n\t\"math\"\n)\n\nconst suggestDidYouMeanTemplate = \"Did you mean %q?\"\n\nvar (\n\tSuggestFlag               "
  },
  {
    "path": "suggestions_test.go",
    "chars": 2818,
    "preview": "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 *test"
  },
  {
    "path": "template.go",
    "chars": 4834,
    "preview": "package cli\n\nvar (\n\thelpNameTemplate    = `{{$v := offset .FullName 6}}{{wrap .FullName 3}}{{if .Usage}} - {{wrap .Usage"
  },
  {
    "path": "testdata/empty.yml",
    "chars": 12,
    "preview": "# empty file"
  },
  {
    "path": "testdata/expected-doc-full.man",
    "chars": 1367,
    "preview": ".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|-"
  },
  {
    "path": "testdata/expected-doc-full.md",
    "chars": 1224,
    "preview": "# 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"
  },
  {
    "path": "testdata/expected-doc-no-authors.md",
    "chars": 1224,
    "preview": "# 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"
  },
  {
    "path": "testdata/expected-doc-no-commands.md",
    "chars": 365,
    "preview": "# 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"
  },
  {
    "path": "testdata/expected-doc-no-flags.md",
    "chars": 1001,
    "preview": "# 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_"
  },
  {
    "path": "testdata/expected-doc-no-usagetext.md",
    "chars": 1261,
    "preview": "# 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"
  },
  {
    "path": "testdata/expected-fish-full.fish",
    "chars": 4346,
    "preview": "# greet fish shell completion\n\nfunction __fish_greet_no_subcommand --description 'Test if there has been any subcommand "
  },
  {
    "path": "testdata/expected-tabular-markdown-custom-app-path.md",
    "chars": 3483,
    "preview": "## CLI interface - greet\n\nDescription of the application.\n\nSome app.\n\n> app [first_arg] [second_arg]\n\nUsage:\n\n```bash\n$ "
  },
  {
    "path": "testdata/expected-tabular-markdown-full.md",
    "chars": 3406,
    "preview": "## CLI interface - greet\n\nDescription of the application.\n\nSome app.\n\n> app [first_arg] [second_arg]\n\nUsage:\n\n```bash\n$ "
  },
  {
    "path": "testdata/godoc-v3.x.txt",
    "chars": 57048,
    "preview": "package cli // import \"github.com/urfave/cli/v3\"\n\nPackage cli provides a minimal framework for creating and organizing c"
  },
  {
    "path": "value_source.go",
    "chars": 5909,
    "preview": "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// typ"
  },
  {
    "path": "value_source_test.go",
    "chars": 7221,
    "preview": "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\"git"
  }
]

About this extraction

This page contains the full source code of the urfave/cli GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 161 files (890.6 KB), approximately 264.1k tokens, and a symbol index with 1011 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!