mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2026-08-24 02:34:19 -05:00
refactor(cli): replace cobra and pflag with minimal internal packages
The CLI framework was the largest remaining third-party chunk (545 kB) and most of its surface went unused - completions are explicitly disabled, templates and command groups never used. Replace both with internal packages mirroring the exact API subset in use: a command tree with persistent flags and nearest-hook semantics, POSIX flag parsing (--flag=value, --flag value, shorthands and grouping, the -- terminator, interspersed positionals, unknown-flag allowlisting for the argocd segment), positional validators, the implicit help command, and the Windows Explorer double-click guard. Help, usage and error output were verified byte-identical against the previous binary across a 47-case golden battery: every command and subcommand help screen, error formats and exit codes, flag styles including flags before the subcommand, and init/print rendering. Shrinks the stripped linux/amd64 binary by 586 kB (13.50 MB -> 12.91 MB; 23.7% below the original 16.93 MB). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qiyvpiy5jR2tyzwZ3zUki5
This commit is contained in:
@@ -52,14 +52,14 @@ build/ # CI build helpers
|
|||||||
|
|
||||||
Key paths inside `src/`:
|
Key paths inside `src/`:
|
||||||
|
|
||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
| ----------------------------- | --------------------------------------------------- |
|
| ------------------------------ | ----------------------------------------------------- |
|
||||||
| `src/segments/` | One `.go` + one `_test.go` per segment |
|
| `src/segments/` | One `.go` + one `_test.go` per segment |
|
||||||
| `src/config/segment_types.go` | Segment type registry (gob + string constants) |
|
| `src/config/segment_types.go` | Segment type registry (gob + string constants) |
|
||||||
| `src/cli/` | CLI commands (Cobra); `root.go` is the entry point |
|
| `src/cli/` | CLI commands (cmdtree); `root.go` is the entry point |
|
||||||
| `src/prompt/engine.go` | Segment rendering loop |
|
| `src/prompt/engine.go` | Segment rendering loop |
|
||||||
| `src/cache/` | Existing TTL/file/command-path cache infrastructure |
|
| `src/cache/` | Existing TTL/file/command-path cache infrastructure |
|
||||||
| `src/runtime/` | `Environment` abstraction + mock |
|
| `src/runtime/` | `Environment` abstraction + mock |
|
||||||
|
|
||||||
## Segment Development
|
## Segment Development
|
||||||
|
|
||||||
@@ -97,10 +97,10 @@ Supported shells: `bash`, `zsh`, `fish`, `powershell`/`pwsh`, `cmd`, `nu`, `elvi
|
|||||||
|
|
||||||
## CLI Commands
|
## CLI Commands
|
||||||
|
|
||||||
CLI commands use [Cobra](https://github.com/spf13/cobra) and live in `src/cli/`. To add a new
|
CLI commands use the internal `src/cmdtree` command tree and live in `src/cli/`. To add a new
|
||||||
command:
|
command:
|
||||||
|
|
||||||
1. Create `src/cli/<name>.go` with a `var <name>Cmd = &cobra.Command{...}`
|
1. Create `src/cli/<name>.go` with a `var <name>Cmd = &cmdtree.Command{...}`
|
||||||
2. Register it in `src/cli/root.go` via `RootCmd.AddCommand(<name>Cmd)`
|
2. Register it in `src/cli/root.go` via `RootCmd.AddCommand(<name>Cmd)`
|
||||||
|
|
||||||
## Caching
|
## Caching
|
||||||
|
|||||||
+4
-4
@@ -1,17 +1,17 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NoArgsOrOneValidArg(cmd *cobra.Command, args []string) error {
|
func NoArgsOrOneValidArg(cmd *cmdtree.Command, args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cobra.ExactArgs(1)(cmd, args); err != nil {
|
if err := cmdtree.ExactArgs(1)(cmd, args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cobra.OnlyValidArgs(cmd, args)
|
return cmdtree.OnlyValidArgs(cmd, args)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -8,10 +8,10 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var authCmd = &cobra.Command{
|
var authCmd = &cmdtree.Command{
|
||||||
Use: "auth [service]",
|
Use: "auth [service]",
|
||||||
Short: "Authenticate against a service",
|
Short: "Authenticate against a service",
|
||||||
Long: `Authenticate against a service.
|
Long: `Authenticate against a service.
|
||||||
@@ -25,7 +25,7 @@ Available services:
|
|||||||
"ytmda",
|
"ytmda",
|
||||||
},
|
},
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+4
-4
@@ -7,14 +7,14 @@ import (
|
|||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
session bool
|
session bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var cacheCmd = &cobra.Command{
|
var cacheCmd = &cmdtree.Command{
|
||||||
Use: "cache [path|clear|ttl|show]",
|
Use: "cache [path|clear|ttl|show]",
|
||||||
Short: "Interact with the oh-my-posh cache",
|
Short: "Interact with the oh-my-posh cache",
|
||||||
Long: `Interact with the oh-my-posh cache.
|
Long: `Interact with the oh-my-posh cache.
|
||||||
@@ -31,8 +31,8 @@ You can do the following:
|
|||||||
cache.TTL,
|
cache.TTL,
|
||||||
"show",
|
"show",
|
||||||
},
|
},
|
||||||
Args: cobra.RangeArgs(1, 2),
|
Args: cmdtree.RangeArgs(1, 2),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+3
-3
@@ -6,10 +6,10 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/segments"
|
"github.com/jandedobbeleer/oh-my-posh/src/segments"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var claudeCmd = &cobra.Command{
|
var claudeCmd = &cmdtree.Command{
|
||||||
Use: "claude",
|
Use: "claude",
|
||||||
Short: "Render a prompt for Claude Code statusline",
|
Short: "Render a prompt for Claude Code statusline",
|
||||||
Long: `Render a prompt for Claude Code statusline integration.
|
Long: `Render a prompt for Claude Code statusline integration.
|
||||||
@@ -22,7 +22,7 @@ Example usage in Claude Code settings:
|
|||||||
"statusLine": {
|
"statusLine": {
|
||||||
"command": "oh-my-posh claude --config ~/.config/ohmyposh/claude.toml"
|
"command": "oh-my-posh claude --config ~/.config/ohmyposh/claude.toml"
|
||||||
}`,
|
}`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: statuslineRun[segments.ClaudeData](
|
Run: statuslineRun[segments.ClaudeData](
|
||||||
shell.CLAUDE,
|
shell.CLAUDE,
|
||||||
cache.CLAUDECACHE,
|
cache.CLAUDECACHE,
|
||||||
|
|||||||
+3
-3
@@ -6,12 +6,12 @@ import (
|
|||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cli/dsc"
|
"github.com/jandedobbeleer/oh-my-posh/src/cli/dsc"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
basedsc "github.com/jandedobbeleer/oh-my-posh/src/dsc"
|
basedsc "github.com/jandedobbeleer/oh-my-posh/src/dsc"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var configCmd = &cobra.Command{
|
var configCmd = &cmdtree.Command{
|
||||||
Use: "config edit",
|
Use: "config edit",
|
||||||
Short: "Interact with the config",
|
Short: "Interact with the config",
|
||||||
Long: `Interact with the config.
|
Long: `Interact with the config.
|
||||||
@@ -21,7 +21,7 @@ You can export or edit the config (via the editor specified in the environment v
|
|||||||
"edit",
|
"edit",
|
||||||
},
|
},
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -19,7 +19,7 @@ var (
|
|||||||
output string
|
output string
|
||||||
)
|
)
|
||||||
|
|
||||||
var exportCmd = &cobra.Command{
|
var exportCmd = &cmdtree.Command{
|
||||||
Use: "export",
|
Use: "export",
|
||||||
Short: "Export your config",
|
Short: "Export your config",
|
||||||
Long: `Export your config.
|
Long: `Export your config.
|
||||||
@@ -35,8 +35,8 @@ Exports the config file "~/myconfig.omp.json" in TOML format and prints the resu
|
|||||||
> oh-my-posh config export --output ~/new_config.omp.json
|
> oh-my-posh config export --output ~/new_config.omp.json
|
||||||
|
|
||||||
Exports the current config to "~/new_config.omp.json" (in JSON format).`,
|
Exports the current config to "~/new_config.omp.json" (in JSON format).`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
if output == "" && format == "" {
|
if output == "" && format == "" {
|
||||||
// usage error
|
// usage error
|
||||||
fmt.Println("neither output path nor export format is specified")
|
fmt.Println("neither output path nor export format is specified")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -20,7 +20,7 @@ var (
|
|||||||
themesDir string
|
themesDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
var dataCmd = &cobra.Command{
|
var dataCmd = &cmdtree.Command{
|
||||||
Use: "data",
|
Use: "data",
|
||||||
Short: "Export a template data file for your config",
|
Short: "Export a template data file for your config",
|
||||||
Long: `Export a template data file for your config.
|
Long: `Export a template data file for your config.
|
||||||
@@ -47,8 +47,8 @@ them into a single sanitized fixture (the most common recorded value per
|
|||||||
segment key wins), and writes it to the given output path. --config is
|
segment key wins), and writes it to the given output path. --config is
|
||||||
ignored in this mode. This is the single command that regenerates
|
ignored in this mode. This is the single command that regenerates
|
||||||
src/prompt/testdata/fixtures - run from src/.`,
|
src/prompt/testdata/fixtures - run from src/.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(cmd *cobra.Command, _ []string) {
|
Run: func(cmd *cmdtree.Command, _ []string) {
|
||||||
cache.Init(os.Getenv("POSH_SHELL"))
|
cache.Init(os.Getenv("POSH_SHELL"))
|
||||||
|
|
||||||
if themesDir != "" {
|
if themesDir != "" {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -25,7 +25,7 @@ var (
|
|||||||
svgBackgroundColor string
|
svgBackgroundColor string
|
||||||
)
|
)
|
||||||
|
|
||||||
var imageCmd = &cobra.Command{
|
var imageCmd = &cmdtree.Command{
|
||||||
Use: "image",
|
Use: "image",
|
||||||
Short: "Export your config to an SVG image",
|
Short: "Export your config to an SVG image",
|
||||||
Long: `Export your config to an SVG image.
|
Long: `Export your config to an SVG image.
|
||||||
@@ -70,8 +70,8 @@ Exports the config to an image file called myconfig.svg in the current working d
|
|||||||
> oh-my-posh config export image --config ~/myconfig.omp.json --output ~/mytheme.svg
|
> oh-my-posh config export image --config ~/myconfig.omp.json --output ~/mytheme.svg
|
||||||
|
|
||||||
Exports the config to an image file ~/mytheme.svg.`,
|
Exports the config to an image file ~/mytheme.svg.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(cmd *cobra.Command, _ []string) {
|
Run: func(cmd *cmdtree.Command, _ []string) {
|
||||||
cache.Init(os.Getenv("POSH_SHELL"))
|
cache.Init(os.Getenv("POSH_SHELL"))
|
||||||
|
|
||||||
setConfigFlag()
|
setConfigFlag()
|
||||||
|
|||||||
+3
-3
@@ -6,12 +6,12 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/segments"
|
"github.com/jandedobbeleer/oh-my-posh/src/segments"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
const copilotServiceName = "copilot"
|
const copilotServiceName = "copilot"
|
||||||
|
|
||||||
var copilotCmd = &cobra.Command{
|
var copilotCmd = &cmdtree.Command{
|
||||||
Use: copilotServiceName,
|
Use: copilotServiceName,
|
||||||
Short: "Render a prompt for GitHub Copilot CLI statusline",
|
Short: "Render a prompt for GitHub Copilot CLI statusline",
|
||||||
Long: `Render a prompt for GitHub Copilot CLI statusline integration.
|
Long: `Render a prompt for GitHub Copilot CLI statusline integration.
|
||||||
@@ -23,7 +23,7 @@ model name, token usage, costs, and more.
|
|||||||
Example usage in GitHub Copilot CLI settings (%USERPROFILE%\.copilot\statusline.cmd):
|
Example usage in GitHub Copilot CLI settings (%USERPROFILE%\.copilot\statusline.cmd):
|
||||||
@echo off
|
@echo off
|
||||||
oh-my-posh copilot --config %USERPROFILE%\.config\ohmyposh\copilot.toml`,
|
oh-my-posh copilot --config %USERPROFILE%\.config\ohmyposh\copilot.toml`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: statuslineRun(
|
Run: statuslineRun(
|
||||||
shell.COPILOTCLI,
|
shell.COPILOTCLI,
|
||||||
cache.COPILOTCLICACHE,
|
cache.COPILOTCLICACHE,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -291,7 +291,7 @@ func TestApplyDataFile_DataDeriveIsNoopOnAnUnmarkedFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPrintAndImageCmd_DataDeriveFlagRegistered(t *testing.T) {
|
func TestPrintAndImageCmd_DataDeriveFlagRegistered(t *testing.T) {
|
||||||
for _, cmd := range []*cobra.Command{printCmd, imageCmd} {
|
for _, cmd := range []*cmdtree.Command{printCmd, imageCmd} {
|
||||||
flag := cmd.Flags().Lookup("data-derive")
|
flag := cmd.Flags().Lookup("data-derive")
|
||||||
require.NotNil(t, flag, "%s must register --data-derive", cmd.Use)
|
require.NotNil(t, flag, "%s must register --data-derive", cmd.Use)
|
||||||
assert.Equal(t, "false", flag.DefValue)
|
assert.Equal(t, "false", flag.DefValue)
|
||||||
|
|||||||
+4
-4
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,12 +27,12 @@ func init() {
|
|||||||
RootCmd.AddCommand(debugCmd)
|
RootCmd.AddCommand(debugCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDebugCmd() *cobra.Command {
|
func createDebugCmd() *cmdtree.Command {
|
||||||
debugCmd := &cobra.Command{
|
debugCmd := &cmdtree.Command{
|
||||||
Use: "debug",
|
Use: "debug",
|
||||||
Short: "Print the prompt in debug mode",
|
Short: "Print the prompt in debug mode",
|
||||||
Long: "Print the prompt in debug mode.",
|
Long: "Print the prompt in debug mode.",
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
log.Enable(plain)
|
log.Enable(plain)
|
||||||
|
|||||||
+3
-3
@@ -3,16 +3,16 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var disableCmd = &cobra.Command{
|
var disableCmd = &cmdtree.Command{
|
||||||
Use: fmt.Sprintf(toggleUse, "disable"),
|
Use: fmt.Sprintf(toggleUse, "disable"),
|
||||||
Short: "Disable a feature",
|
Short: "Disable a feature",
|
||||||
Long: fmt.Sprintf(toggleLong, "Disable"),
|
Long: fmt.Sprintf(toggleLong, "Disable"),
|
||||||
ValidArgs: toggleArgs,
|
ValidArgs: toggleArgs,
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+4
-4
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -23,13 +23,13 @@ var (
|
|||||||
toggleLong = strings.Join(append([]string{toggleHelpText}, toggleArgs...), "\n- ")
|
toggleLong = strings.Join(append([]string{toggleHelpText}, toggleArgs...), "\n- ")
|
||||||
)
|
)
|
||||||
|
|
||||||
var enableCmd = &cobra.Command{
|
var enableCmd = &cmdtree.Command{
|
||||||
Use: fmt.Sprintf(toggleUse, "enable"),
|
Use: fmt.Sprintf(toggleUse, "enable"),
|
||||||
Short: "Enable a feature",
|
Short: "Enable a feature",
|
||||||
Long: fmt.Sprintf(toggleLong, "Enable"),
|
Long: fmt.Sprintf(toggleLong, "Enable"),
|
||||||
ValidArgs: toggleArgs,
|
ValidArgs: toggleArgs,
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
@@ -42,7 +42,7 @@ func init() {
|
|||||||
RootCmd.AddCommand(enableCmd)
|
RootCmd.AddCommand(enableCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleFeature(cmd *cobra.Command, feature string, enable bool) {
|
func toggleFeature(cmd *cmdtree.Command, feature string, enable bool) {
|
||||||
if feature == "" {
|
if feature == "" {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+8
-8
@@ -12,13 +12,13 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
zipFolder string
|
zipFolder string
|
||||||
|
|
||||||
fontCmd = &cobra.Command{
|
fontCmd = &cmdtree.Command{
|
||||||
Use: "font",
|
Use: "font",
|
||||||
Short: "Manage fonts",
|
Short: "Manage fonts",
|
||||||
Long: `Manage fonts.
|
Long: `Manage fonts.
|
||||||
@@ -29,7 +29,7 @@ List the available Nerd Fonts and install one:
|
|||||||
oh-my-posh font install Meslo`,
|
oh-my-posh font install Meslo`,
|
||||||
}
|
}
|
||||||
|
|
||||||
fontListCmd = &cobra.Command{
|
fontListCmd = &cmdtree.Command{
|
||||||
Use: "list",
|
Use: "list",
|
||||||
Short: "List the available Nerd Fonts",
|
Short: "List the available Nerd Fonts",
|
||||||
Long: `List the available Nerd Fonts.
|
Long: `List the available Nerd Fonts.
|
||||||
@@ -37,8 +37,8 @@ List the available Nerd Fonts and install one:
|
|||||||
Prints one font name per line, so it can be searched or piped:
|
Prints one font name per line, so it can be searched or piped:
|
||||||
|
|
||||||
oh-my-posh font list | grep -i mono`,
|
oh-my-posh font list | grep -i mono`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
fonts, err := font.List()
|
fonts, err := font.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -53,7 +53,7 @@ Prints one font name per line, so it can be searched or piped:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fontInstallCmd = &cobra.Command{
|
fontInstallCmd = &cmdtree.Command{
|
||||||
Use: "install <font>",
|
Use: "install <font>",
|
||||||
Short: "Install a Nerd Font",
|
Short: "Install a Nerd Font",
|
||||||
Long: `Install a Nerd Font.
|
Long: `Install a Nerd Font.
|
||||||
@@ -63,8 +63,8 @@ Takes a font name from ` + "`oh-my-posh font list`" + `, a URL, or the path to a
|
|||||||
oh-my-posh font install Meslo
|
oh-my-posh font install Meslo
|
||||||
oh-my-posh font install https://example.com/font.zip
|
oh-my-posh font install https://example.com/font.zip
|
||||||
oh-my-posh font install ./CascadiaCode.zip`,
|
oh-my-posh font install ./CascadiaCode.zip`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cmdtree.ExactArgs(1),
|
||||||
Run: func(_ *cobra.Command, args []string) {
|
Run: func(_ *cmdtree.Command, args []string) {
|
||||||
env := &runtime.Terminal{}
|
env := &runtime.Terminal{}
|
||||||
env.Init(&runtime.Flags{})
|
env.Init(&runtime.Flags{})
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -10,10 +10,10 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
|
|
||||||
color2 "github.com/gookit/color"
|
color2 "github.com/gookit/color"
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var getCmd = &cobra.Command{
|
var getCmd = &cmdtree.Command{
|
||||||
Use: "get [shell|millis|accent|toggles|width]",
|
Use: "get [shell|millis|accent|toggles|width]",
|
||||||
Short: "Get a value from oh-my-posh",
|
Short: "Get a value from oh-my-posh",
|
||||||
Long: `Get a value from oh-my-posh.
|
Long: `Get a value from oh-my-posh.
|
||||||
@@ -34,7 +34,7 @@ This command is used to get the value of the following variables:
|
|||||||
cache.TTL,
|
cache.TTL,
|
||||||
},
|
},
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+7
-7
@@ -8,14 +8,14 @@ import (
|
|||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cli/dsc"
|
"github.com/jandedobbeleer/oh-my-posh/src/cli/dsc"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdflag"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime/path"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -43,8 +43,8 @@ func init() {
|
|||||||
RootCmd.AddCommand(initCmd)
|
RootCmd.AddCommand(initCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createInitCmd() *cobra.Command {
|
func createInitCmd() *cmdtree.Command {
|
||||||
initCmd := &cobra.Command{
|
initCmd := &cmdtree.Command{
|
||||||
Use: "init [bash|zsh|fish|powershell|pwsh|cmd|nu|elvish|xonsh|yash]",
|
Use: "init [bash|zsh|fish|powershell|pwsh|cmd|nu|elvish|xonsh|yash]",
|
||||||
Short: "Initialize your shell and config",
|
Short: "Initialize your shell and config",
|
||||||
Long: `Initialize your shell and config.
|
Long: `Initialize your shell and config.
|
||||||
@@ -52,7 +52,7 @@ func createInitCmd() *cobra.Command {
|
|||||||
See the documentation to initialize your shell: https://ohmyposh.dev/docs/installation/prompt.`,
|
See the documentation to initialize your shell: https://ohmyposh.dev/docs/installation/prompt.`,
|
||||||
ValidArgs: supportedShells,
|
ValidArgs: supportedShells,
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
@@ -143,7 +143,7 @@ func runInit(sh, command string) {
|
|||||||
fmt.Print(output)
|
fmt.Print(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFullCommand(cmd *cobra.Command, args []string) string {
|
func getFullCommand(cmd *cmdtree.Command, args []string) string {
|
||||||
// Start with the command path
|
// Start with the command path
|
||||||
cmdPath := cmd.CommandPath()
|
cmdPath := cmd.CommandPath()
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ func getFullCommand(cmd *cobra.Command, args []string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add flags that were actually set
|
// Add flags that were actually set
|
||||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
cmd.Flags().VisitAll(func(flag *cmdflag.Flag) {
|
||||||
if !flag.Changed {
|
if !flag.Changed {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -6,17 +6,17 @@ import (
|
|||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade"
|
"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var noticeCmd = &cobra.Command{
|
var noticeCmd = &cmdtree.Command{
|
||||||
Use: "notice",
|
Use: "notice",
|
||||||
Short: "Print the upgrade notice when a new version is available.",
|
Short: "Print the upgrade notice when a new version is available.",
|
||||||
Long: "Print the upgrade notice when a new version is available.",
|
Long: "Print the upgrade notice when a new version is available.",
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
env := &runtime.Terminal{}
|
env := &runtime.Terminal{}
|
||||||
env.Init(&runtime.Flags{})
|
env.Init(&runtime.Flags{})
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -40,8 +40,8 @@ func init() {
|
|||||||
RootCmd.AddCommand(printCmd)
|
RootCmd.AddCommand(printCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPrintCmd() *cobra.Command {
|
func createPrintCmd() *cmdtree.Command {
|
||||||
printCmd := &cobra.Command{
|
printCmd := &cmdtree.Command{
|
||||||
Use: "print [debug|primary|secondary|transient|transient-right|right|tooltip|valid|error|preview]",
|
Use: "print [debug|primary|secondary|transient|transient-right|right|tooltip|valid|error|preview]",
|
||||||
Short: "Print the prompt/context",
|
Short: "Print the prompt/context",
|
||||||
Long: "Print one of the prompts based on the location/use-case.",
|
Long: "Print one of the prompts based on the location/use-case.",
|
||||||
@@ -58,7 +58,7 @@ func createPrintCmd() *cobra.Command {
|
|||||||
prompt.PREVIEW,
|
prompt.PREVIEW,
|
||||||
},
|
},
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+6
-6
@@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/build"
|
"github.com/jandedobbeleer/oh-my-posh/src/build"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,14 +27,14 @@ var (
|
|||||||
initialize bool
|
initialize bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var RootCmd = &cobra.Command{
|
var RootCmd = &cmdtree.Command{
|
||||||
Use: "oh-my-posh",
|
Use: "oh-my-posh",
|
||||||
Short: "oh-my-posh is a tool to render your prompt",
|
Short: "oh-my-posh is a tool to render your prompt",
|
||||||
Long: `oh-my-posh is a cross platform tool to render your prompt.
|
Long: `oh-my-posh is a cross platform tool to render your prompt.
|
||||||
It can use the same configuration everywhere to offer a consistent
|
It can use the same configuration everywhere to offer a consistent
|
||||||
experience, regardless of where you are. For a detailed guide
|
experience, regardless of where you are. For a detailed guide
|
||||||
on getting started, have a look at the docs at https://ohmyposh.dev`,
|
on getting started, have a look at the docs at https://ohmyposh.dev`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if initialize {
|
if initialize {
|
||||||
runInit(strings.ToLower(shellName), getFullCommand(cmd, args))
|
runInit(strings.ToLower(shellName), getFullCommand(cmd, args))
|
||||||
return
|
return
|
||||||
@@ -47,7 +47,7 @@ on getting started, have a look at the docs at https://ohmyposh.dev`,
|
|||||||
|
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
},
|
},
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
PersistentPreRun: func(cmd *cmdtree.Command, args []string) {
|
||||||
configEnv := os.Getenv("POSH_CONFIG")
|
configEnv := os.Getenv("POSH_CONFIG")
|
||||||
if configEnv != "" && configFlag == "" {
|
if configEnv != "" && configFlag == "" {
|
||||||
configFlag = configEnv
|
configFlag = configEnv
|
||||||
@@ -65,7 +65,7 @@ on getting started, have a look at the docs at https://ohmyposh.dev`,
|
|||||||
log.Debug("version:", build.Version)
|
log.Debug("version:", build.Version)
|
||||||
log.Debug("command:", getFullCommand(cmd, args))
|
log.Debug("command:", getFullCommand(cmd, args))
|
||||||
},
|
},
|
||||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
PersistentPostRun: func(cmd *cmdtree.Command, args []string) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if exitcode != 0 {
|
if exitcode != 0 {
|
||||||
os.Exit(exitcode)
|
os.Exit(exitcode)
|
||||||
@@ -104,7 +104,7 @@ func Execute() {
|
|||||||
// of milliseconds per prompt. Explorer never passes arguments, so the
|
// of milliseconds per prompt. Explorer never passes arguments, so the
|
||||||
// check is only needed when there are none.
|
// check is only needed when there are none.
|
||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
cobra.MousetrapHelpText = ""
|
cmdtree.ExplorerLaunchHelpText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := RootCmd.Execute(); err != nil {
|
if err := RootCmd.Execute(); err != nil {
|
||||||
|
|||||||
+5
-5
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unix only - used by shells that cannot hold a child's stdin open across
|
// Unix only - used by shells that cannot hold a child's stdin open across
|
||||||
@@ -66,13 +66,13 @@ const (
|
|||||||
// stdout: "<id>\x1f<payload>\x00". \x1f is the ASCII unit separator.
|
// stdout: "<id>\x1f<payload>\x00". \x1f is the ASCII unit separator.
|
||||||
const serveIDMarker = "\x1f"
|
const serveIDMarker = "\x1f"
|
||||||
|
|
||||||
func createServeCmd() *cobra.Command {
|
func createServeCmd() *cmdtree.Command {
|
||||||
serveCmd := &cobra.Command{
|
serveCmd := &cmdtree.Command{
|
||||||
Use: "serve",
|
Use: "serve",
|
||||||
Short: "Start a persistent prompt server that streams prompt updates over stdio",
|
Short: "Start a persistent prompt server that streams prompt updates over stdio",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
if shellName == "" {
|
if shellName == "" {
|
||||||
shellName = shell.GENERIC
|
shellName = shell.GENERIC
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -5,12 +5,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cli/dsc"
|
"github.com/jandedobbeleer/oh-my-posh/src/cli/dsc"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
basedsc "github.com/jandedobbeleer/oh-my-posh/src/dsc"
|
basedsc "github.com/jandedobbeleer/oh-my-posh/src/dsc"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var shellCmd = &cobra.Command{
|
var shellCmd = &cmdtree.Command{
|
||||||
Use: "shell get",
|
Use: "shell get",
|
||||||
Short: "Get the shell name",
|
Short: "Get the shell name",
|
||||||
Long: `Get the shell name.
|
Long: `Get the shell name.
|
||||||
@@ -21,7 +21,7 @@ This command retrieves the name of the current shell being used.`,
|
|||||||
"get",
|
"get",
|
||||||
},
|
},
|
||||||
Args: NoArgsOrOneValidArg,
|
Args: NoArgsOrOneValidArg,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
// statuslineRun returns a cobra Run function for statusline commands.
|
// statuslineRun returns a cobra Run function for statusline commands.
|
||||||
@@ -23,8 +23,8 @@ import (
|
|||||||
// cacheKey is the session cache key under which data is stored.
|
// cacheKey is the session cache key under which data is stored.
|
||||||
// sessionID extracts the session ID from parsed data so it can be set as POSH_SESSION_ID.
|
// sessionID extracts the session ID from parsed data so it can be set as POSH_SESSION_ID.
|
||||||
// defaultCfg is called when no --config flag is provided or parsing fails.
|
// defaultCfg is called when no --config flag is provided or parsing fails.
|
||||||
func statuslineRun[T any](shellConst, cacheKey string, sessionID func(*T) string, defaultCfg func() *config.Config) func(*cobra.Command, []string) {
|
func statuslineRun[T any](shellConst, cacheKey string, sessionID func(*T) string, defaultCfg func() *config.Config) func(*cmdtree.Command, []string) {
|
||||||
return func(cmd *cobra.Command, _ []string) {
|
return func(cmd *cmdtree.Command, _ []string) {
|
||||||
log.Debugf("%s command started", shellConst)
|
log.Debugf("%s command started", shellConst)
|
||||||
|
|
||||||
stdinData, err := io.ReadAll(os.Stdin)
|
stdinData, err := io.ReadAll(os.Stdin)
|
||||||
|
|||||||
+5
-5
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var streamCmd = createStreamCmd()
|
var streamCmd = createStreamCmd()
|
||||||
@@ -18,8 +18,8 @@ func init() {
|
|||||||
RootCmd.AddCommand(streamCmd)
|
RootCmd.AddCommand(streamCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createStreamCmd() *cobra.Command {
|
func createStreamCmd() *cmdtree.Command {
|
||||||
streamCmd := &cobra.Command{
|
streamCmd := &cmdtree.Command{
|
||||||
Use: "stream",
|
Use: "stream",
|
||||||
Short: "Stream the prompt with incremental updates",
|
Short: "Stream the prompt with incremental updates",
|
||||||
Long: `Stream the primary prompt with incremental updates as segments complete.
|
Long: `Stream the primary prompt with incremental updates as segments complete.
|
||||||
@@ -29,8 +29,8 @@ Records prefixed with a record separator byte (\x1e) carry the transient prompt,
|
|||||||
which shells cache so no additional CLI call is needed on line acceptance.
|
which shells cache so no additional CLI call is needed on line acceptance.
|
||||||
The shell can read records incrementally and update the display.
|
The shell can read records incrementally and update the display.
|
||||||
Command exits when all segments are resolved.`,
|
Command exits when all segments are resolved.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
if shellName == "" {
|
if shellName == "" {
|
||||||
shellName = shell.GENERIC
|
shellName = shell.GENERIC
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -5,16 +5,16 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var toggleCmd = &cobra.Command{
|
var toggleCmd = &cmdtree.Command{
|
||||||
Use: "toggle segment1 segment2 ...",
|
Use: "toggle segment1 segment2 ...",
|
||||||
Short: "Toggle one or more segments on/off",
|
Short: "Toggle one or more segments on/off",
|
||||||
Long: "Toggle one or more segments on/off on the fly. Multiple segments can be specified separated by spaces.",
|
Long: "Toggle one or more segments on/off on the fly. Multiple segments can be specified separated by spaces.",
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cmdtree.MinimumNArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
+4
-4
@@ -11,12 +11,12 @@ import (
|
|||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade"
|
"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade/tui"
|
"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade/tui"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/text"
|
"github.com/jandedobbeleer/oh-my-posh/src/text"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -24,12 +24,12 @@ var (
|
|||||||
auto bool
|
auto bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var upgradeCmd = &cobra.Command{
|
var upgradeCmd = &cmdtree.Command{
|
||||||
Use: "upgrade",
|
Use: "upgrade",
|
||||||
Short: "Upgrade when a new version is available.",
|
Short: "Upgrade when a new version is available.",
|
||||||
Long: "Upgrade when a new version is available.",
|
Long: "Upgrade when a new version is available.",
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
var startTime time.Time
|
var startTime time.Time
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
|
|||||||
+4
-4
@@ -4,19 +4,19 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/build"
|
"github.com/jandedobbeleer/oh-my-posh/src/build"
|
||||||
"github.com/spf13/cobra"
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
verbose bool
|
verbose bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var versionCmd = &cobra.Command{
|
var versionCmd = &cmdtree.Command{
|
||||||
Use: "version",
|
Use: "version",
|
||||||
Short: "Print the version",
|
Short: "Print the version",
|
||||||
Long: "Print the version number of oh-my-posh.",
|
Long: "Print the version number of oh-my-posh.",
|
||||||
Args: cobra.NoArgs,
|
Args: cmdtree.NoArgs,
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
Run: func(_ *cmdtree.Command, _ []string) {
|
||||||
if !verbose {
|
if !verbose {
|
||||||
fmt.Println(build.Version)
|
fmt.Println(build.Version)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,448 @@
|
|||||||
|
// Package cmdflag is a minimal POSIX-style command-line flag parser covering
|
||||||
|
// the API surface oh-my-posh uses: typed Var registration, POSIX-style
|
||||||
|
// parsing (--flag=value, --flag value, shorthands, the -- terminator,
|
||||||
|
// interspersed positionals), hidden flags, and usage rendering matching
|
||||||
|
// common CLI flag conventions byte for byte for the flag types in use.
|
||||||
|
package cmdflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorHandling int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ContinueOnError ErrorHandling = iota
|
||||||
|
ExitOnError
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
boolType = "bool"
|
||||||
|
trueStr = "true"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Value is the interface to the dynamic value stored in a flag.
|
||||||
|
type Value interface {
|
||||||
|
String() string
|
||||||
|
Set(string) error
|
||||||
|
Type() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Flag struct {
|
||||||
|
Name string
|
||||||
|
Shorthand string
|
||||||
|
Usage string
|
||||||
|
Value Value
|
||||||
|
DefValue string
|
||||||
|
Hidden bool
|
||||||
|
Changed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlagSet struct {
|
||||||
|
name string
|
||||||
|
flags map[string]*Flag
|
||||||
|
shorthands map[byte]*Flag
|
||||||
|
order []*Flag
|
||||||
|
args []string
|
||||||
|
|
||||||
|
ParseErrorsAllowlist struct {
|
||||||
|
UnknownFlags bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFlagSet(name string, _ ErrorHandling) *FlagSet {
|
||||||
|
return &FlagSet{
|
||||||
|
name: name,
|
||||||
|
flags: make(map[string]*Flag),
|
||||||
|
shorthands: make(map[byte]*Flag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// value implementations
|
||||||
|
|
||||||
|
type stringValue struct{ p *string }
|
||||||
|
|
||||||
|
func (v stringValue) String() string { return *v.p }
|
||||||
|
func (v stringValue) Set(s string) error { *v.p = s; return nil }
|
||||||
|
func (v stringValue) Type() string { return "string" }
|
||||||
|
|
||||||
|
type boolValue struct{ p *bool }
|
||||||
|
|
||||||
|
func (v boolValue) String() string { return strconv.FormatBool(*v.p) }
|
||||||
|
func (v boolValue) Set(s string) error {
|
||||||
|
b, err := strconv.ParseBool(s)
|
||||||
|
*v.p = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (v boolValue) Type() string { return boolType }
|
||||||
|
|
||||||
|
type intValue struct{ p *int }
|
||||||
|
|
||||||
|
func (v intValue) String() string { return strconv.Itoa(*v.p) }
|
||||||
|
func (v intValue) Set(s string) error {
|
||||||
|
i, err := strconv.ParseInt(s, 0, 64)
|
||||||
|
*v.p = int(i)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (v intValue) Type() string { return "int" }
|
||||||
|
|
||||||
|
type float64Value struct{ p *float64 }
|
||||||
|
|
||||||
|
func (v float64Value) String() string { return strconv.FormatFloat(*v.p, 'g', -1, 64) }
|
||||||
|
func (v float64Value) Set(s string) error {
|
||||||
|
f, err := strconv.ParseFloat(s, 64)
|
||||||
|
*v.p = f
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (v float64Value) Type() string { return "float64" }
|
||||||
|
|
||||||
|
// registration
|
||||||
|
|
||||||
|
func (f *FlagSet) Var(value Value, name, shorthand, usage string) *Flag {
|
||||||
|
flag := &Flag{
|
||||||
|
Name: name,
|
||||||
|
Shorthand: shorthand,
|
||||||
|
Usage: usage,
|
||||||
|
Value: value,
|
||||||
|
DefValue: value.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
f.flags[name] = flag
|
||||||
|
f.order = append(f.order, flag)
|
||||||
|
|
||||||
|
if shorthand != "" {
|
||||||
|
f.shorthands[shorthand[0]] = flag
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) StringVar(p *string, name, value, usage string) {
|
||||||
|
f.StringVarP(p, name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) StringVarP(p *string, name, shorthand, value, usage string) {
|
||||||
|
*p = value
|
||||||
|
f.Var(stringValue{p}, name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) String(name, value, usage string) *string {
|
||||||
|
p := new(string)
|
||||||
|
f.StringVar(p, name, value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
||||||
|
f.BoolVarP(p, name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
||||||
|
*p = value
|
||||||
|
f.Var(boolValue{p}, name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
|
||||||
|
f.IntVarP(p, name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) {
|
||||||
|
*p = value
|
||||||
|
f.Var(intValue{p}, name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
|
||||||
|
*p = value
|
||||||
|
f.Var(float64Value{p}, name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inspection
|
||||||
|
|
||||||
|
func (f *FlagSet) Lookup(name string) *Flag {
|
||||||
|
return f.flags[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) ShorthandLookup(name string) *Flag {
|
||||||
|
if name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.shorthands[name[0]]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) Changed(name string) bool {
|
||||||
|
flag := f.flags[name]
|
||||||
|
return flag != nil && flag.Changed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) MarkHidden(name string) error {
|
||||||
|
flag := f.flags[name]
|
||||||
|
if flag == nil {
|
||||||
|
return fmt.Errorf("flag %q does not exist", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Hidden = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitAll visits the flags in registration order rather than
|
||||||
|
// lexicographically: the sole caller formats a command line and is
|
||||||
|
// order-insensitive, and usage rendering sorts separately.
|
||||||
|
func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
||||||
|
for _, flag := range f.order {
|
||||||
|
fn(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFlagSet adds flags from another set that are not yet present.
|
||||||
|
func (f *FlagSet) AddFlagSet(other *FlagSet) {
|
||||||
|
if other == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
other.VisitAll(func(flag *Flag) {
|
||||||
|
if f.flags[flag.Name] == nil {
|
||||||
|
f.flags[flag.Name] = flag
|
||||||
|
f.order = append(f.order, flag)
|
||||||
|
|
||||||
|
if flag.Shorthand != "" && f.shorthands[flag.Shorthand[0]] == nil {
|
||||||
|
f.shorthands[flag.Shorthand[0]] = flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) HasFlags() bool {
|
||||||
|
return len(f.order) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) HasAvailableFlags() bool {
|
||||||
|
for _, flag := range f.order {
|
||||||
|
if !flag.Hidden {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) Args() []string {
|
||||||
|
return f.args
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsing
|
||||||
|
|
||||||
|
func (f *FlagSet) Parse(arguments []string) error {
|
||||||
|
f.args = make([]string, 0, len(arguments))
|
||||||
|
|
||||||
|
for len(arguments) > 0 {
|
||||||
|
arg := arguments[0]
|
||||||
|
arguments = arguments[1:]
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case arg == "--":
|
||||||
|
f.args = append(f.args, arguments...)
|
||||||
|
return nil
|
||||||
|
case strings.HasPrefix(arg, "--"):
|
||||||
|
var err error
|
||||||
|
arguments, err = f.parseLong(arg[2:], arguments)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(arg, "-") && len(arg) > 1:
|
||||||
|
var err error
|
||||||
|
arguments, err = f.parseShort(arg[1:], arguments)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
f.args = append(f.args, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) parseLong(name string, rest []string) ([]string, error) {
|
||||||
|
value := ""
|
||||||
|
hasValue := false
|
||||||
|
|
||||||
|
if i := strings.Index(name, "="); i >= 0 {
|
||||||
|
value = name[i+1:]
|
||||||
|
name = name[:i]
|
||||||
|
hasValue = true
|
||||||
|
}
|
||||||
|
|
||||||
|
flag := f.flags[name]
|
||||||
|
if flag == nil {
|
||||||
|
if !f.ParseErrorsAllowlist.UnknownFlags {
|
||||||
|
return rest, fmt.Errorf("unknown flag: --%s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// an unknown flag given as "--flag value" swallows the
|
||||||
|
// value token unless the next token is itself a flag
|
||||||
|
if !hasValue && len(rest) > 0 && !strings.HasPrefix(rest[0], "-") {
|
||||||
|
return rest[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return rest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case hasValue:
|
||||||
|
case flag.Value.Type() == boolType:
|
||||||
|
value = trueStr
|
||||||
|
case len(rest) > 0:
|
||||||
|
value = rest[0]
|
||||||
|
rest = rest[1:]
|
||||||
|
default:
|
||||||
|
return rest, fmt.Errorf("flag needs an argument: --%s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := flag.Value.Set(value); err != nil {
|
||||||
|
return rest, fmt.Errorf("invalid argument %q for \"--%s\" flag: %v", value, flag.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Changed = true
|
||||||
|
return rest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlagSet) parseShort(shorthands string, rest []string) ([]string, error) {
|
||||||
|
for len(shorthands) > 0 {
|
||||||
|
c := shorthands[0]
|
||||||
|
|
||||||
|
flag := f.shorthands[c]
|
||||||
|
if flag == nil {
|
||||||
|
if f.ParseErrorsAllowlist.UnknownFlags {
|
||||||
|
// drop the remainder of the group and a
|
||||||
|
// separate value token unless it is itself a flag
|
||||||
|
if len(shorthands) == 1 && len(rest) > 0 && !strings.HasPrefix(rest[0], "-") {
|
||||||
|
return rest[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return rest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return rest, fmt.Errorf("unknown shorthand flag: %q in -%s", c, shorthands)
|
||||||
|
}
|
||||||
|
|
||||||
|
value := ""
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(shorthands) > 2 && shorthands[1] == '=':
|
||||||
|
value = shorthands[2:]
|
||||||
|
shorthands = ""
|
||||||
|
case flag.Value.Type() == boolType:
|
||||||
|
value = trueStr
|
||||||
|
shorthands = shorthands[1:]
|
||||||
|
case len(shorthands) > 1:
|
||||||
|
value = shorthands[1:]
|
||||||
|
shorthands = ""
|
||||||
|
case len(rest) > 0:
|
||||||
|
value = rest[0]
|
||||||
|
rest = rest[1:]
|
||||||
|
shorthands = ""
|
||||||
|
default:
|
||||||
|
return rest, fmt.Errorf("flag needs an argument: %q in -%s", c, shorthands)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := flag.Value.Set(value); err != nil {
|
||||||
|
return rest, fmt.Errorf("invalid argument %q for \"-%s, --%s\" flag: %v", value, flag.Shorthand, flag.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return rest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// usage rendering
|
||||||
|
|
||||||
|
// FlagUsages renders the non-hidden flags sorted by name, shorthand column,
|
||||||
|
// type name after the flag, defaults in parentheses when they differ from
|
||||||
|
// the zero value, usage aligned in a single column.
|
||||||
|
func (f *FlagSet) FlagUsages() string {
|
||||||
|
lines := make([]string, 0, len(f.order))
|
||||||
|
maxlen := 0
|
||||||
|
|
||||||
|
flags := make([]*Flag, len(f.order))
|
||||||
|
copy(flags, f.order)
|
||||||
|
sortFlags(flags)
|
||||||
|
|
||||||
|
for _, flag := range flags {
|
||||||
|
if flag.Hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var line string
|
||||||
|
if flag.Shorthand != "" {
|
||||||
|
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag.Shorthand == "" {
|
||||||
|
line = fmt.Sprintf(" --%s", flag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if name := typeName(flag); name != "" {
|
||||||
|
line += " " + name
|
||||||
|
}
|
||||||
|
|
||||||
|
line += "\x00"
|
||||||
|
if len(line) > maxlen {
|
||||||
|
maxlen = len(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
line += flag.Usage
|
||||||
|
if defValue, ok := defaultValue(flag); ok {
|
||||||
|
line += fmt.Sprintf(" (default %s)", defValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
for _, line := range lines {
|
||||||
|
sidx := strings.Index(line, "\x00")
|
||||||
|
sb.WriteString(line[:sidx])
|
||||||
|
// the gap is maxlen-sidx+2 spaces wide to match the implicit
|
||||||
|
// separators of a Fprintln(left, spacing, usage)-style layout
|
||||||
|
sb.WriteString(strings.Repeat(" ", maxlen-sidx+2))
|
||||||
|
sb.WriteString(line[sidx+1:])
|
||||||
|
sb.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortFlags(flags []*Flag) {
|
||||||
|
for i := 1; i < len(flags); i++ {
|
||||||
|
for j := i; j > 0 && flags[j].Name < flags[j-1].Name; j-- {
|
||||||
|
flags[j], flags[j-1] = flags[j-1], flags[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeName(flag *Flag) string {
|
||||||
|
switch flag.Value.Type() {
|
||||||
|
case boolType:
|
||||||
|
return ""
|
||||||
|
case "float64":
|
||||||
|
return "float"
|
||||||
|
case "int64":
|
||||||
|
return "int"
|
||||||
|
default:
|
||||||
|
return flag.Value.Type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultValue(flag *Flag) (string, bool) {
|
||||||
|
switch flag.Value.Type() {
|
||||||
|
case boolType:
|
||||||
|
return flag.DefValue, flag.DefValue == trueStr
|
||||||
|
case "string":
|
||||||
|
return fmt.Sprintf("%q", flag.DefValue), flag.DefValue != ""
|
||||||
|
default:
|
||||||
|
return flag.DefValue, flag.DefValue != "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package cmdflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseStyles(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
Expected string
|
||||||
|
Args []string
|
||||||
|
Rest []string
|
||||||
|
Number int
|
||||||
|
Bool bool
|
||||||
|
}{
|
||||||
|
{Case: "long with space", Args: []string{"--name", "x"}, Expected: "x", Rest: []string{}},
|
||||||
|
{Case: "long with equals", Args: []string{"--name=x"}, Expected: "x", Rest: []string{}},
|
||||||
|
{Case: "shorthand with space", Args: []string{"-n", "x"}, Expected: "x", Rest: []string{}},
|
||||||
|
{Case: "shorthand joined", Args: []string{"-nx"}, Expected: "x", Rest: []string{}},
|
||||||
|
{Case: "shorthand with equals", Args: []string{"-n=x"}, Expected: "x", Rest: []string{}},
|
||||||
|
{Case: "bool does not eat value", Args: []string{"--flag", "positional"}, Bool: true, Rest: []string{"positional"}},
|
||||||
|
{Case: "terminator", Args: []string{"--", "--name", "x"}, Rest: []string{"--name", "x"}},
|
||||||
|
{Case: "interspersed", Args: []string{"a", "--name", "x", "b"}, Expected: "x", Rest: []string{"a", "b"}},
|
||||||
|
{Case: "int value", Args: []string{"--count", "42"}, Number: 42, Rest: []string{}},
|
||||||
|
{Case: "combined bool shorthands", Args: []string{"-fv"}, Bool: true, Rest: []string{}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
var name string
|
||||||
|
var flag, verbose bool
|
||||||
|
var count int
|
||||||
|
|
||||||
|
fs := NewFlagSet("test", ContinueOnError)
|
||||||
|
fs.StringVarP(&name, "name", "n", "", "")
|
||||||
|
fs.BoolVarP(&flag, "flag", "f", false, "")
|
||||||
|
fs.BoolVarP(&verbose, "verbose", "v", false, "")
|
||||||
|
fs.IntVar(&count, "count", 0, "")
|
||||||
|
|
||||||
|
err := fs.Parse(tc.Args)
|
||||||
|
assert.NoError(t, err, tc.Case)
|
||||||
|
assert.Equal(t, tc.Expected, name, tc.Case)
|
||||||
|
assert.Equal(t, tc.Bool, flag, tc.Case)
|
||||||
|
assert.Equal(t, tc.Number, count, tc.Case)
|
||||||
|
assert.Equal(t, tc.Rest, fs.Args(), tc.Case)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseErrors(t *testing.T) {
|
||||||
|
fs := NewFlagSet("test", ContinueOnError)
|
||||||
|
var name string
|
||||||
|
fs.StringVar(&name, "name", "", "")
|
||||||
|
|
||||||
|
err := fs.Parse([]string{"--unknown"})
|
||||||
|
assert.EqualError(t, err, "unknown flag: --unknown")
|
||||||
|
|
||||||
|
err = fs.Parse([]string{"-x"})
|
||||||
|
assert.EqualError(t, err, `unknown shorthand flag: 'x' in -x`)
|
||||||
|
|
||||||
|
err = fs.Parse([]string{"--name"})
|
||||||
|
assert.EqualError(t, err, "flag needs an argument: --name")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnknownFlagsAllowlist(t *testing.T) {
|
||||||
|
// the argocd segment parses ARGOCD_OPTS this way
|
||||||
|
fs := NewFlagSet("test", ContinueOnError)
|
||||||
|
fs.ParseErrorsAllowlist.UnknownFlags = true
|
||||||
|
fs.String("config", "", "")
|
||||||
|
|
||||||
|
err := fs.Parse([]string{"--grpc-web", "--server", "foo.com", "--config", "x", "--insecure"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "x", fs.Lookup("config").Value.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangedAndDefaults(t *testing.T) {
|
||||||
|
fs := NewFlagSet("test", ContinueOnError)
|
||||||
|
var escape bool
|
||||||
|
fs.BoolVar(&escape, "escape", true, "escape the output")
|
||||||
|
|
||||||
|
assert.False(t, fs.Changed("escape"))
|
||||||
|
assert.NoError(t, fs.Parse([]string{"--escape=false"}))
|
||||||
|
assert.True(t, fs.Changed("escape"))
|
||||||
|
assert.False(t, escape)
|
||||||
|
assert.Equal(t, "true", fs.Lookup("escape").DefValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlagUsages(t *testing.T) {
|
||||||
|
fs := NewFlagSet("test", ContinueOnError)
|
||||||
|
var name, pswd string
|
||||||
|
var force, escape bool
|
||||||
|
var width int
|
||||||
|
|
||||||
|
fs.StringVarP(&name, "config", "c", "", "config file path")
|
||||||
|
fs.BoolVarP(&force, "force", "f", false, "force rendering the segments")
|
||||||
|
fs.BoolVar(&escape, "escape", true, "escape the ANSI sequences for the shell")
|
||||||
|
fs.IntVarP(&width, "terminal-width", "w", 0, "width of the terminal")
|
||||||
|
fs.StringVar(&pswd, "pswd", "", "hidden flag")
|
||||||
|
_ = fs.MarkHidden("pswd")
|
||||||
|
|
||||||
|
expected := ` -c, --config string config file path
|
||||||
|
--escape escape the ANSI sequences for the shell (default true)
|
||||||
|
-f, --force force rendering the segments
|
||||||
|
-w, --terminal-width int width of the terminal
|
||||||
|
`
|
||||||
|
assert.Equal(t, expected, fs.FlagUsages())
|
||||||
|
}
|
||||||
@@ -0,0 +1,538 @@
|
|||||||
|
// Package cmdtree is a minimal command-line command tree implementation covering
|
||||||
|
// the API surface oh-my-posh uses: a command tree with persistent flags and
|
||||||
|
// hooks, POSIX flag parsing via the sibling cmdflag package, positional
|
||||||
|
// argument validators, and help/usage output matching common CLI framework
|
||||||
|
// conventions byte for byte for the features in use.
|
||||||
|
package cmdtree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExplorerLaunchHelpText is shown on Windows when the binary is launched from
|
||||||
|
// Explorer instead of a terminal. Setting it to "" disables the check.
|
||||||
|
var ExplorerLaunchHelpText = `This is a command line tool.
|
||||||
|
|
||||||
|
You need to open cmd.exe and run it from there.
|
||||||
|
`
|
||||||
|
|
||||||
|
type PositionalArgs func(cmd *Command, args []string) error
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
out io.Writer
|
||||||
|
flags *cmdflag.FlagSet
|
||||||
|
parent *Command
|
||||||
|
PersistentPostRun func(cmd *Command, args []string)
|
||||||
|
pflags *cmdflag.FlagSet
|
||||||
|
PersistentPreRun func(cmd *Command, args []string)
|
||||||
|
Args PositionalArgs
|
||||||
|
Run func(cmd *Command, args []string)
|
||||||
|
Example string
|
||||||
|
Long string
|
||||||
|
Short string
|
||||||
|
Use string
|
||||||
|
ValidArgs []string
|
||||||
|
commands []*Command
|
||||||
|
requiredFlags []string
|
||||||
|
Aliases []string
|
||||||
|
setArgs []string
|
||||||
|
Hidden bool
|
||||||
|
helpRequested bool
|
||||||
|
CompletionOptions struct{ DisableDefaultCmd bool }
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOut redirects help output to a caller-supplied writer instead of stdout.
|
||||||
|
func (c *Command) SetOut(w io.Writer) {
|
||||||
|
c.out = w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) outWriter() io.Writer {
|
||||||
|
for cmd := c; cmd != nil; cmd = cmd.parent {
|
||||||
|
if cmd.out != nil {
|
||||||
|
return cmd.out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) Name() string {
|
||||||
|
name, _, _ := strings.Cut(c.Use, " ")
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) CommandPath() string {
|
||||||
|
if c.parent == nil {
|
||||||
|
return c.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.parent.CommandPath() + " " + c.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) UseLine() string {
|
||||||
|
useLine := c.Use
|
||||||
|
if c.parent != nil {
|
||||||
|
useLine = c.parent.CommandPath() + " " + c.Use
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Flags().HasAvailableFlags() && !strings.Contains(useLine, "[flags]") {
|
||||||
|
useLine += " [flags]"
|
||||||
|
}
|
||||||
|
|
||||||
|
return useLine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) Root() *Command {
|
||||||
|
if c.parent == nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.parent.Root()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) AddCommand(cmds ...*Command) {
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
cmd.parent = c
|
||||||
|
c.commands = append(c.commands, cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) Flags() *cmdflag.FlagSet {
|
||||||
|
if c.flags == nil {
|
||||||
|
c.flags = cmdflag.NewFlagSet(c.Name(), cmdflag.ContinueOnError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) PersistentFlags() *cmdflag.FlagSet {
|
||||||
|
if c.pflags == nil {
|
||||||
|
c.pflags = cmdflag.NewFlagSet(c.Name(), cmdflag.ContinueOnError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.pflags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) SetArgs(args []string) {
|
||||||
|
c.setArgs = args
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkPersistentFlagRequired only applies to a flag registered on this
|
||||||
|
// command's own persistent set and errors otherwise.
|
||||||
|
func (c *Command) MarkPersistentFlagRequired(name string) error {
|
||||||
|
flag := c.PersistentFlags().Lookup(name)
|
||||||
|
if flag == nil {
|
||||||
|
return fmt.Errorf("no such flag -%v", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.requiredFlags = append(c.requiredFlags, name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) hasSubCommands() bool {
|
||||||
|
for _, cmd := range c.commands {
|
||||||
|
if !cmd.Hidden && cmd.Name() != "help" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) findChild(name string) *Command {
|
||||||
|
for _, cmd := range c.commands {
|
||||||
|
if cmd.Name() == name {
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(cmd.Aliases, name) {
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergedFlags returns the command's local flags plus every ancestor's
|
||||||
|
// persistent flags, with the auto help flag registered.
|
||||||
|
func (c *Command) mergedFlags() *cmdflag.FlagSet {
|
||||||
|
merged := cmdflag.NewFlagSet(c.Name(), cmdflag.ContinueOnError)
|
||||||
|
merged.AddFlagSet(c.Flags())
|
||||||
|
|
||||||
|
for cmd := c; cmd != nil; cmd = cmd.parent {
|
||||||
|
merged.AddFlagSet(cmd.pflags)
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
// inheritedFlags returns the ancestors' persistent flags, rendered in help
|
||||||
|
// output as the "Global Flags" section.
|
||||||
|
func (c *Command) inheritedFlags() *cmdflag.FlagSet {
|
||||||
|
inherited := cmdflag.NewFlagSet(c.Name(), cmdflag.ContinueOnError)
|
||||||
|
|
||||||
|
for cmd := c.parent; cmd != nil; cmd = cmd.parent {
|
||||||
|
inherited.AddFlagSet(cmd.pflags)
|
||||||
|
}
|
||||||
|
|
||||||
|
return inherited
|
||||||
|
}
|
||||||
|
|
||||||
|
// localFlags returns the command's own flags: declared local flags, its own
|
||||||
|
// persistent flags, and - only when already initialized - the help flag,
|
||||||
|
// so the help flag is only listed once a caller has actually requested help.
|
||||||
|
// The unknown-help-topic path renders root usage without a help flag.
|
||||||
|
func (c *Command) localFlags() *cmdflag.FlagSet {
|
||||||
|
local := cmdflag.NewFlagSet(c.Name(), cmdflag.ContinueOnError)
|
||||||
|
local.AddFlagSet(c.Flags())
|
||||||
|
local.AddFlagSet(c.pflags)
|
||||||
|
|
||||||
|
return local
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) registerHelpFlag() {
|
||||||
|
if c.Flags().Lookup("help") != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Flags().BoolVarP(&c.helpRequested, "help", "h", false, "help for "+c.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute parses os.Args (or SetArgs), routes to the addressed subcommand,
|
||||||
|
// validates positionals, and runs the hooks and the command.
|
||||||
|
func (c *Command) Execute() error {
|
||||||
|
if c.parent == nil {
|
||||||
|
checkExplorerLaunch()
|
||||||
|
c.ensureHelpCommand()
|
||||||
|
}
|
||||||
|
|
||||||
|
args := c.setArgs
|
||||||
|
if args == nil {
|
||||||
|
args = os.Args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd, remaining, err := c.route(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
fmt.Fprintf(os.Stderr, "Run '%s --help' for usage.\n", c.CommandPath())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd.execute(remaining)
|
||||||
|
}
|
||||||
|
|
||||||
|
// route walks the command tree: at each level the first token that is not a
|
||||||
|
// flag (accounting for flags that consume a value) addresses a child.
|
||||||
|
func (c *Command) route(args []string) (*Command, []string, error) {
|
||||||
|
current := c
|
||||||
|
|
||||||
|
for {
|
||||||
|
name, ok := firstPositional(current, args)
|
||||||
|
if !ok {
|
||||||
|
return current, args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
child := current.findChild(name)
|
||||||
|
if child == nil {
|
||||||
|
if current == c && len(current.commands) > 0 {
|
||||||
|
return nil, nil, fmt.Errorf("unknown command %q for %q", name, c.CommandPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
return current, args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
args = removeFirst(args, name)
|
||||||
|
current = child
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstPositional finds the first argument that cannot be a flag or a flag
|
||||||
|
// value at this command level.
|
||||||
|
func firstPositional(c *Command, args []string) (string, bool) {
|
||||||
|
flags := c.mergedFlags()
|
||||||
|
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
arg := args[i]
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case arg == "--":
|
||||||
|
return "", false
|
||||||
|
case strings.HasPrefix(arg, "--"):
|
||||||
|
name, _, hasValue := strings.Cut(arg[2:], "=")
|
||||||
|
if hasValue {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag := flags.Lookup(name); flag != nil && flag.Value.Type() != "bool" {
|
||||||
|
i++ // skip the flag's value
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(arg, "-") && len(arg) > 1:
|
||||||
|
if strings.Contains(arg, "=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
shorthand := arg[len(arg)-1:]
|
||||||
|
if flag := flags.ShorthandLookup(shorthand); flag != nil && flag.Value.Type() != "bool" {
|
||||||
|
i++ // skip the flag's value
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return arg, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeFirst(args []string, value string) []string {
|
||||||
|
result := make([]string, 0, len(args)-1)
|
||||||
|
removed := false
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
if !removed && arg == value {
|
||||||
|
removed = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) execute(args []string) error {
|
||||||
|
c.registerHelpFlag()
|
||||||
|
flags := c.mergedFlags()
|
||||||
|
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
return c.flagError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.helpRequested {
|
||||||
|
return c.Help()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range c.requiredFlags {
|
||||||
|
if !flags.Changed(name) {
|
||||||
|
return c.flagError(fmt.Errorf("required flag(s) \"%s\" not set", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
positionals := flags.Args()
|
||||||
|
|
||||||
|
if c.Args != nil {
|
||||||
|
if err := c.Args(c, positionals); err != nil {
|
||||||
|
return c.flagError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Run == nil {
|
||||||
|
return c.Help()
|
||||||
|
}
|
||||||
|
|
||||||
|
if hook := c.findHook(func(cmd *Command) func(*Command, []string) { return cmd.PersistentPreRun }); hook != nil {
|
||||||
|
hook(c, positionals)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Run(c, positionals)
|
||||||
|
|
||||||
|
if hook := c.findHook(func(cmd *Command) func(*Command, []string) { return cmd.PersistentPostRun }); hook != nil {
|
||||||
|
hook(c, positionals)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// findHook returns the nearest defined hook walking up the tree, so only the
|
||||||
|
// closest one runs.
|
||||||
|
func (c *Command) findHook(get func(*Command) func(*Command, []string)) func(*Command, []string) {
|
||||||
|
for cmd := c; cmd != nil; cmd = cmd.parent {
|
||||||
|
if hook := get(cmd); hook != nil {
|
||||||
|
return hook
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) flagError(err error) error {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
// print the usage string via Println, leaving a trailing blank line
|
||||||
|
fmt.Fprintln(os.Stderr, c.usageString())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureHelpCommand adds the implicit help command if none is registered.
|
||||||
|
func (c *Command) ensureHelpCommand() {
|
||||||
|
if c.findChild("help") != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AddCommand(&Command{
|
||||||
|
Use: "help [command]",
|
||||||
|
Short: "Help about any command",
|
||||||
|
Long: `Help provides help for any command in the application.
|
||||||
|
Simply type ` + c.Name() + ` help [path to command] for full details.`,
|
||||||
|
Run: func(_ *Command, args []string) {
|
||||||
|
target := c
|
||||||
|
for _, name := range args {
|
||||||
|
child := target.findChild(name)
|
||||||
|
if child == nil {
|
||||||
|
fmt.Printf("Unknown help topic %#q\n", args)
|
||||||
|
fmt.Fprint(os.Stderr, c.usageString())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
target = child
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = target.Help()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// help output
|
||||||
|
|
||||||
|
func (c *Command) Help() error {
|
||||||
|
c.registerHelpFlag()
|
||||||
|
|
||||||
|
long := c.Long
|
||||||
|
if long == "" {
|
||||||
|
long = c.Short
|
||||||
|
}
|
||||||
|
|
||||||
|
if long != "" {
|
||||||
|
fmt.Fprintln(c.outWriter(), strings.TrimRight(long, "\n"))
|
||||||
|
fmt.Fprintln(c.outWriter())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(c.outWriter(), c.usageString())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) usageString() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
sb.WriteString("Usage:\n")
|
||||||
|
if c.Run != nil || !c.hasSubCommands() {
|
||||||
|
sb.WriteString(" " + c.UseLine() + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.hasSubCommands() {
|
||||||
|
sb.WriteString(" " + c.CommandPath() + " [command]\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Aliases) > 0 {
|
||||||
|
sb.WriteString("\nAliases:\n")
|
||||||
|
sb.WriteString(" " + c.Name() + ", " + strings.Join(c.Aliases, ", ") + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Example != "" {
|
||||||
|
sb.WriteString("\nExamples:\n")
|
||||||
|
sb.WriteString(c.Example + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.hasSubCommands() {
|
||||||
|
sb.WriteString("\nAvailable Commands:\n")
|
||||||
|
|
||||||
|
commands := make([]*Command, 0, len(c.commands))
|
||||||
|
for _, cmd := range c.commands {
|
||||||
|
if !cmd.Hidden {
|
||||||
|
commands = append(commands, cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(commands, func(i, j int) bool { return commands[i].Name() < commands[j].Name() })
|
||||||
|
|
||||||
|
padding := 11
|
||||||
|
for _, cmd := range commands {
|
||||||
|
if len(cmd.Name())+2 > padding {
|
||||||
|
padding = len(cmd.Name()) + 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
fmt.Fprintf(&sb, " %-*s %s\n", padding, cmd.Name(), cmd.Short)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if local := c.localFlags(); local.HasAvailableFlags() {
|
||||||
|
sb.WriteString("\nFlags:\n")
|
||||||
|
sb.WriteString(local.FlagUsages())
|
||||||
|
}
|
||||||
|
|
||||||
|
if inherited := c.inheritedFlags(); inherited.HasAvailableFlags() {
|
||||||
|
sb.WriteString("\nGlobal Flags:\n")
|
||||||
|
sb.WriteString(inherited.FlagUsages())
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.hasSubCommands() {
|
||||||
|
sb.WriteString("\nUse \"" + c.CommandPath() + " [command] --help\" for more information about a command.\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// positional argument validators
|
||||||
|
|
||||||
|
func NoArgs(cmd *Command, args []string) error {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExactArgs(n int) PositionalArgs {
|
||||||
|
return func(_ *Command, args []string) error {
|
||||||
|
if len(args) != n {
|
||||||
|
return fmt.Errorf("accepts %d arg(s), received %d", n, len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MinimumNArgs(n int) PositionalArgs {
|
||||||
|
return func(_ *Command, args []string) error {
|
||||||
|
if len(args) < n {
|
||||||
|
return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RangeArgs(minimum, maximum int) PositionalArgs {
|
||||||
|
return func(_ *Command, args []string) error {
|
||||||
|
if len(args) < minimum || len(args) > maximum {
|
||||||
|
return fmt.Errorf("accepts between %d and %d arg(s), received %d", minimum, maximum, len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func OnlyValidArgs(cmd *Command, args []string) error {
|
||||||
|
if len(cmd.ValidArgs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
if !contains(cmd.ValidArgs, arg) {
|
||||||
|
return fmt.Errorf("invalid argument %q for %q", arg, cmd.CommandPath())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(values []string, value string) bool {
|
||||||
|
return slices.Contains(values, value)
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package cmdtree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testTree() (root *Command, ran *string) {
|
||||||
|
ran = new(string)
|
||||||
|
|
||||||
|
root = &Command{
|
||||||
|
Use: "root",
|
||||||
|
Run: func(_ *Command, _ []string) { *ran = "root" },
|
||||||
|
}
|
||||||
|
|
||||||
|
child := &Command{
|
||||||
|
Use: "child",
|
||||||
|
Run: func(_ *Command, args []string) { *ran = "child:" + join(args) },
|
||||||
|
}
|
||||||
|
|
||||||
|
grandchild := &Command{
|
||||||
|
Use: "grandchild",
|
||||||
|
Run: func(_ *Command, args []string) { *ran = "grandchild:" + join(args) },
|
||||||
|
}
|
||||||
|
|
||||||
|
root.AddCommand(child)
|
||||||
|
child.AddCommand(grandchild)
|
||||||
|
|
||||||
|
return root, ran
|
||||||
|
}
|
||||||
|
|
||||||
|
func join(args []string) string {
|
||||||
|
result := ""
|
||||||
|
for i, arg := range args {
|
||||||
|
if i > 0 {
|
||||||
|
result += " "
|
||||||
|
}
|
||||||
|
result += arg
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouting(t *testing.T) {
|
||||||
|
root, ran := testTree()
|
||||||
|
root.SetArgs([]string{"child", "grandchild", "pos"})
|
||||||
|
assert.NoError(t, root.Execute())
|
||||||
|
assert.Equal(t, "grandchild:pos", *ran)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoutingWithFlagBeforeCommand(t *testing.T) {
|
||||||
|
root, ran := testTree()
|
||||||
|
var config string
|
||||||
|
root.PersistentFlags().StringVarP(&config, "config", "c", "", "")
|
||||||
|
|
||||||
|
root.SetArgs([]string{"--config", "x", "child", "positional"})
|
||||||
|
assert.NoError(t, root.Execute())
|
||||||
|
assert.Equal(t, "child:positional", *ran)
|
||||||
|
assert.Equal(t, "x", config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnknownCommand(t *testing.T) {
|
||||||
|
root, _ := testTree()
|
||||||
|
root.SetArgs([]string{"bogus"})
|
||||||
|
assert.EqualError(t, root.Execute(), `unknown command "bogus" for "root"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPersistentFlagInheritance(t *testing.T) {
|
||||||
|
root, _ := testTree()
|
||||||
|
var trace bool
|
||||||
|
root.PersistentFlags().BoolVar(&trace, "trace", false, "")
|
||||||
|
|
||||||
|
root.SetArgs([]string{"child", "--trace"})
|
||||||
|
assert.NoError(t, root.Execute())
|
||||||
|
assert.True(t, trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPersistentHooksRunOnce(t *testing.T) {
|
||||||
|
var order []string
|
||||||
|
|
||||||
|
root := &Command{
|
||||||
|
Use: "root",
|
||||||
|
PersistentPreRun: func(_ *Command, _ []string) { order = append(order, "pre") },
|
||||||
|
PersistentPostRun: func(_ *Command, _ []string) {
|
||||||
|
order = append(order, "post")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
child := &Command{
|
||||||
|
Use: "child",
|
||||||
|
Run: func(_ *Command, _ []string) { order = append(order, "run") },
|
||||||
|
}
|
||||||
|
|
||||||
|
root.AddCommand(child)
|
||||||
|
root.SetArgs([]string{"child"})
|
||||||
|
assert.NoError(t, root.Execute())
|
||||||
|
assert.Equal(t, []string{"pre", "run", "post"}, order)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArgsValidators(t *testing.T) {
|
||||||
|
cmd := &Command{Use: "cmd"}
|
||||||
|
|
||||||
|
assert.NoError(t, NoArgs(cmd, nil))
|
||||||
|
assert.EqualError(t, NoArgs(cmd, []string{"x"}), `unknown command "x" for "cmd"`)
|
||||||
|
|
||||||
|
assert.NoError(t, ExactArgs(1)(cmd, []string{"a"}))
|
||||||
|
assert.EqualError(t, ExactArgs(1)(cmd, nil), "accepts 1 arg(s), received 0")
|
||||||
|
|
||||||
|
assert.EqualError(t, MinimumNArgs(1)(cmd, nil), "requires at least 1 arg(s), only received 0")
|
||||||
|
assert.EqualError(t, RangeArgs(1, 2)(cmd, nil), "accepts between 1 and 2 arg(s), received 0")
|
||||||
|
|
||||||
|
cmd.ValidArgs = []string{"get", "set"}
|
||||||
|
assert.NoError(t, OnlyValidArgs(cmd, []string{"get"}))
|
||||||
|
assert.EqualError(t, OnlyValidArgs(cmd, []string{"bogus"}), `invalid argument "bogus" for "cmd"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShorthandShadowing(t *testing.T) {
|
||||||
|
// print defines -s stack-count while root defines -s shell; the
|
||||||
|
// subcommand's local flag must win
|
||||||
|
root := &Command{Use: "root"}
|
||||||
|
var shell string
|
||||||
|
root.Flags().StringVarP(&shell, "shell", "s", "", "")
|
||||||
|
|
||||||
|
var stack int
|
||||||
|
child := &Command{Use: "child", Run: func(_ *Command, _ []string) {}}
|
||||||
|
child.Flags().IntVarP(&stack, "stack-count", "s", 0, "")
|
||||||
|
root.AddCommand(child)
|
||||||
|
|
||||||
|
root.SetArgs([]string{"child", "-s", "3"})
|
||||||
|
assert.NoError(t, root.Execute())
|
||||||
|
assert.Equal(t, 3, stack)
|
||||||
|
assert.Equal(t, "", shell)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package cmdtree
|
||||||
|
|
||||||
|
func checkExplorerLaunch() {}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package cmdtree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// checkExplorerLaunch detects a double-click launch from Explorer: there is
|
||||||
|
// no console to read the output, so print an explanation, linger, and exit.
|
||||||
|
func checkExplorerLaunch() {
|
||||||
|
if ExplorerLaunchHelpText == "" || !startedByExplorer() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(ExplorerLaunchHelpText)
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startedByExplorer() bool {
|
||||||
|
pid := windows.GetCurrentProcessId()
|
||||||
|
|
||||||
|
snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() { _ = windows.CloseHandle(snapshot) }()
|
||||||
|
|
||||||
|
var entry windows.ProcessEntry32
|
||||||
|
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||||
|
|
||||||
|
var parentID uint32
|
||||||
|
|
||||||
|
for err = windows.Process32First(snapshot, &entry); err == nil; err = windows.Process32Next(snapshot, &entry) {
|
||||||
|
if entry.ProcessID == pid {
|
||||||
|
parentID = entry.ParentProcessID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parentID == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for err = windows.Process32First(snapshot, &entry); err == nil; err = windows.Process32Next(snapshot, &entry) {
|
||||||
|
if entry.ProcessID != parentID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := windows.UTF16ToString(entry.ExeFile[:])
|
||||||
|
return strings.EqualFold(name, "explorer.exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
+4
-4
@@ -5,8 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
"github.com/jandedobbeleer/oh-my-posh/src/cache"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdtree"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -23,13 +23,13 @@ type resource interface {
|
|||||||
Test(input string) error
|
Test(input string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func Command(r resource) *cobra.Command {
|
func Command(r resource) *cmdtree.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cmdtree.Command{
|
||||||
Use: "dsc",
|
Use: "dsc",
|
||||||
Short: "Manage Oh My Posh DSC (Desired State Configuration)",
|
Short: "Manage Oh My Posh DSC (Desired State Configuration)",
|
||||||
Long: "Manage Oh My Posh DSC (Desired State Configuration).",
|
Long: "Manage Oh My Posh DSC (Desired State Configuration).",
|
||||||
ValidArgs: []string{"get", "set", "test", "schema", "export"},
|
ValidArgs: []string{"get", "set", "test", "schema", "export"},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cmdtree.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
_ = cmd.Help()
|
_ = cmd.Help()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ require (
|
|||||||
github.com/lucasb-eyer/go-colorful v1.4.0
|
github.com/lucasb-eyer/go-colorful v1.4.0
|
||||||
github.com/pelletier/go-toml/v2 v2.4.3
|
github.com/pelletier/go-toml/v2 v2.4.3
|
||||||
github.com/shirou/gopsutil/v4 v4.26.6
|
github.com/shirou/gopsutil/v4 v4.26.6
|
||||||
github.com/spf13/cobra v1.10.2
|
|
||||||
github.com/spf13/pflag v1.0.10
|
|
||||||
go.yaml.in/yaml/v3 v3.0.5
|
go.yaml.in/yaml/v3 v3.0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,7 +49,6 @@ require (
|
|||||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
github.com/buger/jsonparser v1.1.2 // indirect
|
github.com/buger/jsonparser v1.1.2 // indirect
|
||||||
github.com/ebitengine/purego v0.10.0 // indirect
|
github.com/ebitengine/purego v0.10.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
|
||||||
github.com/pb33f/ordered-map/v2 v2.3.1 // indirect
|
github.com/pb33f/ordered-map/v2 v2.3.1 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
|
|||||||
-10
@@ -18,7 +18,6 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
|
|||||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
|
github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
|
||||||
github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -39,8 +38,6 @@ github.com/gookit/color v1.6.1 h1:KoTnDxJPRgrL0SoX0f8rCFg2zI0t4E3GZZBMo2nN8LU=
|
|||||||
github.com/gookit/color v1.6.1/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
|
github.com/gookit/color v1.6.1/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
|
||||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
|
||||||
github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg=
|
github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg=
|
||||||
github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I=
|
github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -70,7 +67,6 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
|
|||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
github.com/shirou/gopsutil/v4 v4.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs=
|
github.com/shirou/gopsutil/v4 v4.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs=
|
||||||
@@ -79,11 +75,6 @@ github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp
|
|||||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
|
||||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
|
||||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||||
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||||
@@ -100,7 +91,6 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM
|
|||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
|
||||||
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
||||||
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s=
|
go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s=
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/cmdflag"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||||
"github.com/spf13/pflag"
|
|
||||||
yaml "go.yaml.in/yaml/v3"
|
yaml "go.yaml.in/yaml/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ func (a *Argocd) getConfigPath() string {
|
|||||||
|
|
||||||
func (a *Argocd) getConfigFromOpts() string {
|
func (a *Argocd) getConfigFromOpts() string {
|
||||||
// don't exit/panic when encountering invalid flags
|
// don't exit/panic when encountering invalid flags
|
||||||
flags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
|
flags := cmdflag.NewFlagSet(os.Args[0], cmdflag.ContinueOnError)
|
||||||
// ignore other valid and invalid flags
|
// ignore other valid and invalid flags
|
||||||
flags.ParseErrorsAllowlist.UnknownFlags = true
|
flags.ParseErrorsAllowlist.UnknownFlags = true
|
||||||
// only care about config
|
// only care about config
|
||||||
|
|||||||
Reference in New Issue
Block a user