diff --git a/README.md b/README.md index 358d910..a3b5026 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,19 @@ The following configuration options are available in either as a command-line ar --prompt-suffix or prompt_suffix A suffix that is added to the end of the prompt. + +--json + Output the results in JSON format. The keys of the JSON result are + branchInfo, branchStatus, color, promptPrefix, and promptSuffix. + + Example: + { + "branchInfo": "main", + "branchStatus": "", + "color": "green", + "promptPrefix": "  ", + "promptSuffix": "" + } ``` #### Specifying colors diff --git a/integration/gps_test.go b/integration/git_prompt_string_test.go similarity index 75% rename from integration/gps_test.go rename to integration/git_prompt_string_test.go index be2a896..8ff1efa 100644 --- a/integration/gps_test.go +++ b/integration/git_prompt_string_test.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "testing" ) @@ -76,6 +77,93 @@ func TestGitPromptString(t *testing.T) { {"configs", []string{}, fmt.Sprintf("\x1b[31m git-prompt-string error(unmarshal config): \"toml: expected character %s\"\x1b[0m", escapedEqualSign), []string{"GIT_PROMPT_STRING_CONFIG=invalid_syntax.toml"}, errors.New("exit status 1")}, {"norepo", []string{"--config=NONE"}, "", nil, nil}, + + // json + { + "bare", + []string{"--config=NONE", "--json"}, + strings.TrimSpace(` +{ + "branchInfo": "BARE:main", + "branchStatus": "", + "color": "bright-black", + "promptPrefix": "  ", + "promptSuffix": "" +} +`), nil, nil, + }, + {"no_upstream_remote", []string{"--config=NONE", "--json"}, strings.TrimSpace(` +{ + "branchInfo": "main → mikesmithgh/test/main", + "branchStatus": "", + "color": "bright-black", + "promptPrefix": "  ", + "promptSuffix": "" +} + `), nil, nil}, + {"git_dir", []string{"--config=NONE", "--json"}, strings.TrimSpace(` +{ + "branchInfo": "GIT_DIR!", + "branchStatus": "", + "color": "bright-black", + "promptPrefix": "  ", + "promptSuffix": "" +} + `), nil, nil}, + {"clean", []string{"--config=NONE", "--json", "--prompt-prefix=a"}, strings.TrimSpace(` +{ + "branchInfo": "main", + "branchStatus": "", + "color": "green", + "promptPrefix": "a", + "promptSuffix": "" +} + `), nil, nil}, + {"tag", []string{"--config=NONE", "--json", "--prompt-suffix=z"}, strings.TrimSpace(` +{ + "branchInfo": "(v1.0.0)", + "branchStatus": "", + "color": "bright-black", + "promptPrefix": "  ", + "promptSuffix": "z" +} + `), nil, nil}, + {"dirty", []string{"--config=NONE", "--json", "--color-dirty=CustomRed"}, strings.TrimSpace(` +{ + "branchInfo": "main", + "branchStatus": " *", + "color": "CustomRed", + "promptPrefix": "  ", + "promptSuffix": "" +} + `), nil, nil}, + {"conflict_diverged", []string{"--config=NONE", "--json"}, strings.TrimSpace(` +{ + "branchInfo": "main", + "branchStatus": " ↕ ↑[1] ↓[1]", + "color": "yellow", + "promptPrefix": "  ", + "promptSuffix": "" +} + `), nil, nil}, + {"untracked", []string{"--config=NONE", "--json"}, strings.TrimSpace(` +{ + "branchInfo": "main", + "branchStatus": " *", + "color": "magenta", + "promptPrefix": "  ", + "promptSuffix": "" +} + `), nil, nil}, + {"sparse", []string{"--config=NONE", "--json"}, strings.TrimSpace(` +{ + "branchInfo": "main|SPARSE", + "branchStatus": "", + "color": "green", + "promptPrefix": "  ", + "promptSuffix": "" +} + `), nil, nil}, } for _, test := range tests { diff --git a/main.go b/main.go index a068674..3aec3a3 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "flag" "fmt" "os" @@ -34,6 +35,7 @@ var ( colorUntracked = flag.String("color-untracked", "magenta", "The color of the prompt when there are untracked files in the\nworking directory.") colorNoUpstream = flag.String("color-no-upstream", "bright-black", "The color of the prompt when there is no remote upstream branch.\n") colorMerging = flag.String("color-merging", "blue", "The color of the prompt during a merge, rebase, cherry-pick,\nrevert, or bisect.") + jsonFormat = flag.Bool("json", false, "Output the results in JSON format. The keys of the JSON result are\nbranchInfo, branchStatus, color, promptPrefix, and promptSuffix.\n\nExample:\n{\n \"branchInfo\": \"main\",\n \"branchStatus\": \"\",\n \"color\": \"green\",\n \"promptPrefix\": \"  \",\n \"promptSuffix\": \"\"\n}") versionFlag = flag.Bool("version", false, "Print version information for git-prompt-string.") ) @@ -189,10 +191,33 @@ func main() { if err != nil { util.ErrMsg("branch info", err) } - branchStatus, promptColor, err := gitRepo.BranchStatus(cfg) + branchStatus, statusColor, err := gitRepo.BranchStatus(cfg) if err != nil { util.ErrMsg("branch status", err) } - fmt.Printf("%s%s%s%s%s%s", promptColor, cfg.PromptPrefix, branchInfo, branchStatus, cfg.PromptSuffix, resetColor) + if *jsonFormat { + color := "" + if !cfg.ColorDisabled { + color = statusColor + } + output := map[string]string{ + "branchInfo": branchInfo, + "branchStatus": branchStatus, + "promptPrefix": cfg.PromptPrefix, + "promptSuffix": cfg.PromptSuffix, + "color": color, + } + jsonOutput, err := json.MarshalIndent(output, "", " ") + if err != nil { + util.ErrMsg("marshal json", err) + } + fmt.Print(string(jsonOutput)) + } else { + promptColor, err := color.Color(strings.Split(statusColor, " ")...) + if err != nil { + util.ErrMsg("prompt color", err) + } + fmt.Printf("%s%s%s%s%s%s", promptColor, cfg.PromptPrefix, branchInfo, branchStatus, cfg.PromptSuffix, resetColor) + } } diff --git a/pkg/git/repo.go b/pkg/git/repo.go index cea7e02..6602ae6 100644 --- a/pkg/git/repo.go +++ b/pkg/git/repo.go @@ -7,7 +7,6 @@ import ( "path/filepath" "strings" - "github.com/mikesmithgh/git-prompt-string/pkg/color" "github.com/mikesmithgh/git-prompt-string/pkg/config" "github.com/mikesmithgh/git-prompt-string/pkg/util" ) @@ -195,11 +194,7 @@ func (g *GitRepo) BranchStatus(cfg config.GitPromptStringConfig) (string, string statusColor := "" if g.IsInBareRepo || g.IsInGitDir { - c, err := color.Color(strings.Split(cfg.ColorNoUpstream, " ")...) - if err != nil { - util.ErrMsg("color no upstream", err) - } - return status, c, nil + return status, cfg.ColorNoUpstream, nil } cleanWorkingTree, err := HasCleanWorkingTree() @@ -220,24 +215,15 @@ func (g *GitRepo) BranchStatus(cfg config.GitPromptStringConfig) (string, string } if cleanWorkingTree { - statusColor, err = color.Color(strings.Split(cfg.ColorClean, " ")...) - if err != nil { - util.ErrMsg("color clean", err) - } + statusColor = cfg.ColorClean } if ahead > 0 { - statusColor, err = color.Color(strings.Split(cfg.ColorDelta, " ")...) - if err != nil { - util.ErrMsg("color delta ahead", err) - } + statusColor = cfg.ColorDelta status = fmt.Sprintf(cfg.AheadFormat, ahead) } if behind > 0 { - statusColor, err = color.Color(strings.Split(cfg.ColorDelta, " ")...) - if err != nil { - util.ErrMsg("color delta behind", err) - } + statusColor = cfg.ColorDelta status = fmt.Sprintf(cfg.BehindFormat, behind) } @@ -246,32 +232,20 @@ func (g *GitRepo) BranchStatus(cfg config.GitPromptStringConfig) (string, string } if g.ShortSha == "" { - statusColor, err = color.Color(strings.Split(cfg.ColorNoUpstream, " ")...) - if err != nil { - util.ErrMsg("color no upstream", err) - } + statusColor = cfg.ColorNoUpstream } if g.PromptMergeStatus != "" { - statusColor, err = color.Color(strings.Split(cfg.ColorMerging, " ")...) - if err != nil { - util.ErrMsg("color merging", err) - } + statusColor = cfg.ColorMerging } if hasUntracked { - statusColor, err = color.Color(strings.Split(cfg.ColorUntracked, " ")...) - if err != nil { - util.ErrMsg("color untracked", err) - } + statusColor = cfg.ColorUntracked status = fmt.Sprintf("*%s", status) } if !cleanWorkingTree && !hasUntracked { - statusColor, err = color.Color(strings.Split(cfg.ColorDirty, " ")...) - if err != nil { - util.ErrMsg("color dirty", err) - } + statusColor = cfg.ColorDirty status = fmt.Sprintf("*%s", status) } if status != "" {