mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-11-09 20:44:03 -08:00
parent
1c908a8ce6
commit
7a6478269c
|
@ -35,7 +35,6 @@ require (
|
||||||
github.com/goccy/go-yaml v1.11.3
|
github.com/goccy/go-yaml v1.11.3
|
||||||
github.com/gookit/goutil v0.6.16
|
github.com/gookit/goutil v0.6.16
|
||||||
github.com/hashicorp/hcl/v2 v2.21.0
|
github.com/hashicorp/hcl/v2 v2.21.0
|
||||||
github.com/mattn/go-runewidth v0.0.16
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2
|
github.com/pelletier/go-toml/v2 v2.2.2
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
|
@ -79,6 +78,7 @@ require (
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
|
|
@ -111,6 +111,8 @@ const (
|
||||||
UntrackedModes properties.Property = "untracked_modes"
|
UntrackedModes properties.Property = "untracked_modes"
|
||||||
// IgnoreSubmodules list the optional ignore-submodules mode per repo
|
// IgnoreSubmodules list the optional ignore-submodules mode per repo
|
||||||
IgnoreSubmodules properties.Property = "ignore_submodules"
|
IgnoreSubmodules properties.Property = "ignore_submodules"
|
||||||
|
// MappedBranches allows overriding certain branches with an icon/text
|
||||||
|
MappedBranches properties.Property = "mapped_branches"
|
||||||
|
|
||||||
DETACHED = "(detached)"
|
DETACHED = "(detached)"
|
||||||
BRANCHPREFIX = "ref: refs/heads/"
|
BRANCHPREFIX = "ref: refs/heads/"
|
||||||
|
@ -333,7 +335,7 @@ func (g *Git) getBareRepoInfo() {
|
||||||
head := g.FileContents(g.workingDir, "HEAD")
|
head := g.FileContents(g.workingDir, "HEAD")
|
||||||
branchIcon := g.props.GetString(BranchIcon, "\uE0A0")
|
branchIcon := g.props.GetString(BranchIcon, "\uE0A0")
|
||||||
g.Ref = strings.Replace(head, "ref: refs/heads/", "", 1)
|
g.Ref = strings.Replace(head, "ref: refs/heads/", "", 1)
|
||||||
g.HEAD = fmt.Sprintf("%s%s", branchIcon, g.Ref)
|
g.HEAD = fmt.Sprintf("%s%s", branchIcon, g.formatBranch(g.Ref))
|
||||||
if !g.props.GetBool(FetchUpstreamIcon, false) {
|
if !g.props.GetBool(FetchUpstreamIcon, false) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -550,23 +552,28 @@ func (g *Git) setGitStatus() {
|
||||||
g.Working.add(workingCode)
|
g.Working.add(workingCode)
|
||||||
g.Staging.add(stagingCode)
|
g.Staging.add(stagingCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HASH = "# branch.oid "
|
HASH = "# branch.oid "
|
||||||
REF = "# branch.head "
|
REF = "# branch.head "
|
||||||
UPSTREAM = "# branch.upstream "
|
UPSTREAM = "# branch.upstream "
|
||||||
BRANCHSTATUS = "# branch.ab "
|
BRANCHSTATUS = "# branch.ab "
|
||||||
)
|
)
|
||||||
|
|
||||||
// firstly assume that upstream is gone
|
// firstly assume that upstream is gone
|
||||||
g.UpstreamGone = true
|
g.UpstreamGone = true
|
||||||
statusFormats := g.props.GetKeyValueMap(StatusFormats, map[string]string{})
|
statusFormats := g.props.GetKeyValueMap(StatusFormats, map[string]string{})
|
||||||
|
|
||||||
g.Working = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
|
g.Working = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
|
||||||
g.Staging = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
|
g.Staging = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
|
||||||
|
|
||||||
untrackedMode := g.getUntrackedFilesMode()
|
untrackedMode := g.getUntrackedFilesMode()
|
||||||
args := []string{"status", untrackedMode, "--branch", "--porcelain=2"}
|
args := []string{"status", untrackedMode, "--branch", "--porcelain=2"}
|
||||||
ignoreSubmodulesMode := g.getIgnoreSubmodulesMode()
|
ignoreSubmodulesMode := g.getIgnoreSubmodulesMode()
|
||||||
if len(ignoreSubmodulesMode) > 0 {
|
if len(ignoreSubmodulesMode) > 0 {
|
||||||
args = append(args, ignoreSubmodulesMode)
|
args = append(args, ignoreSubmodulesMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := g.getGitCommandOutput(args...)
|
output := g.getGitCommandOutput(args...)
|
||||||
for _, line := range strings.Split(output, "\n") {
|
for _, line := range strings.Split(output, "\n") {
|
||||||
if strings.HasPrefix(line, HASH) && len(line) >= len(HASH)+7 {
|
if strings.HasPrefix(line, HASH) && len(line) >= len(HASH)+7 {
|
||||||
|
@ -574,16 +581,19 @@ func (g *Git) setGitStatus() {
|
||||||
g.Hash = line[len(HASH):]
|
g.Hash = line[len(HASH):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(line, REF) && len(line) > len(REF) {
|
if strings.HasPrefix(line, REF) && len(line) > len(REF) {
|
||||||
g.Ref = line[len(REF):]
|
g.Ref = line[len(REF):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(line, UPSTREAM) && len(line) > len(UPSTREAM) {
|
if strings.HasPrefix(line, UPSTREAM) && len(line) > len(UPSTREAM) {
|
||||||
// status reports upstream, but upstream may be gone (must check BRANCHSTATUS)
|
// status reports upstream, but upstream may be gone (must check BRANCHSTATUS)
|
||||||
g.Upstream = line[len(UPSTREAM):]
|
g.Upstream = line[len(UPSTREAM):]
|
||||||
g.UpstreamGone = true
|
g.UpstreamGone = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(line, BRANCHSTATUS) && len(line) > len(BRANCHSTATUS) {
|
if strings.HasPrefix(line, BRANCHSTATUS) && len(line) > len(BRANCHSTATUS) {
|
||||||
status := line[len(BRANCHSTATUS):]
|
status := line[len(BRANCHSTATUS):]
|
||||||
splitted := strings.Split(status, " ")
|
splitted := strings.Split(status, " ")
|
||||||
|
@ -596,6 +606,7 @@ func (g *Git) setGitStatus() {
|
||||||
g.UpstreamGone = false
|
g.UpstreamGone = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
addToStatus(line)
|
addToStatus(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -615,7 +626,7 @@ func (g *Git) setGitHEADContext() {
|
||||||
g.Detached = true
|
g.Detached = true
|
||||||
g.setPrettyHEADName()
|
g.setPrettyHEADName()
|
||||||
} else {
|
} else {
|
||||||
head := g.formatHEAD(g.Ref)
|
head := g.formatBranch(g.Ref)
|
||||||
g.HEAD = fmt.Sprintf("%s%s", branchIcon, head)
|
g.HEAD = fmt.Sprintf("%s%s", branchIcon, head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +644,7 @@ func (g *Git) setGitHEADContext() {
|
||||||
origin = formatDetached()
|
origin = formatDetached()
|
||||||
} else {
|
} else {
|
||||||
head = strings.Replace(head, "refs/heads/", "", 1)
|
head = strings.Replace(head, "refs/heads/", "", 1)
|
||||||
origin = branchIcon + g.formatHEAD(head)
|
origin = branchIcon + g.formatBranch(head)
|
||||||
}
|
}
|
||||||
return origin
|
return origin
|
||||||
}
|
}
|
||||||
|
@ -642,7 +653,7 @@ func (g *Git) setGitHEADContext() {
|
||||||
g.Rebase = true
|
g.Rebase = true
|
||||||
origin := getPrettyNameOrigin("rebase-merge/head-name")
|
origin := getPrettyNameOrigin("rebase-merge/head-name")
|
||||||
onto := g.getGitRefFileSymbolicName("rebase-merge/onto")
|
onto := g.getGitRefFileSymbolicName("rebase-merge/onto")
|
||||||
onto = g.formatHEAD(onto)
|
onto = g.formatBranch(onto)
|
||||||
step := g.FileContents(g.workingDir, "rebase-merge/msgnum")
|
step := g.FileContents(g.workingDir, "rebase-merge/msgnum")
|
||||||
total := g.FileContents(g.workingDir, "rebase-merge/end")
|
total := g.FileContents(g.workingDir, "rebase-merge/end")
|
||||||
icon := g.props.GetString(RebaseIcon, "\uE728 ")
|
icon := g.props.GetString(RebaseIcon, "\uE728 ")
|
||||||
|
@ -680,7 +691,7 @@ func (g *Git) setGitHEADContext() {
|
||||||
theirs = g.formatSHA(matches["theirs"])
|
theirs = g.formatSHA(matches["theirs"])
|
||||||
default:
|
default:
|
||||||
headIcon = branchIcon
|
headIcon = branchIcon
|
||||||
theirs = g.formatHEAD(matches["theirs"])
|
theirs = g.formatBranch(matches["theirs"])
|
||||||
}
|
}
|
||||||
g.HEAD = fmt.Sprintf("%s%s%s into %s", icon, headIcon, theirs, formatDetached())
|
g.HEAD = fmt.Sprintf("%s%s%s into %s", icon, headIcon, theirs, formatDetached())
|
||||||
return
|
return
|
||||||
|
@ -732,15 +743,6 @@ func (g *Git) setGitHEADContext() {
|
||||||
g.HEAD = formatDetached()
|
g.HEAD = formatDetached()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Git) formatHEAD(head string) string {
|
|
||||||
maxLength := g.props.GetInt(BranchMaxLength, 0)
|
|
||||||
if maxLength == 0 || len(head) < maxLength {
|
|
||||||
return head
|
|
||||||
}
|
|
||||||
symbol := g.props.GetString(TruncateSymbol, "")
|
|
||||||
return head[0:maxLength] + symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Git) formatSHA(sha string) string {
|
func (g *Git) formatSHA(sha string) string {
|
||||||
if len(sha) <= 7 {
|
if len(sha) <= 7 {
|
||||||
return sha
|
return sha
|
||||||
|
@ -765,7 +767,7 @@ func (g *Git) setPrettyHEADName() {
|
||||||
if strings.HasPrefix(HEADRef, BRANCHPREFIX) {
|
if strings.HasPrefix(HEADRef, BRANCHPREFIX) {
|
||||||
branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX)
|
branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX)
|
||||||
g.Ref = branchName
|
g.Ref = branchName
|
||||||
g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(BranchIcon, "\uE0A0"), g.formatHEAD(branchName))
|
g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(BranchIcon, "\uE0A0"), g.formatBranch(branchName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// no branch, points to commit
|
// no branch, points to commit
|
||||||
|
|
|
@ -140,23 +140,27 @@ func (p *Plastic) getHeadChangeset() int {
|
||||||
func (p *Plastic) setSelector() {
|
func (p *Plastic) setSelector() {
|
||||||
var ref string
|
var ref string
|
||||||
selector := p.FileContents(p.plasticWorkspaceFolder+"/.plastic/", "plastic.selector")
|
selector := p.FileContents(p.plasticWorkspaceFolder+"/.plastic/", "plastic.selector")
|
||||||
|
|
||||||
// changeset
|
// changeset
|
||||||
ref = p.parseChangesetSelector(selector)
|
ref = p.parseChangesetSelector(selector)
|
||||||
if len(ref) > 0 {
|
if len(ref) > 0 {
|
||||||
p.Selector = fmt.Sprintf("%s%s", p.props.GetString(CommitIcon, "\uF417"), ref)
|
p.Selector = fmt.Sprintf("%s%s", p.props.GetString(CommitIcon, "\uF417"), ref)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to label
|
// fallback to label
|
||||||
ref = p.parseLabelSelector(selector)
|
ref = p.parseLabelSelector(selector)
|
||||||
if len(ref) > 0 {
|
if len(ref) > 0 {
|
||||||
p.Selector = fmt.Sprintf("%s%s", p.props.GetString(TagIcon, "\uF412"), ref)
|
p.Selector = fmt.Sprintf("%s%s", p.props.GetString(TagIcon, "\uF412"), ref)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to branch/smartbranch
|
// fallback to branch/smartbranch
|
||||||
ref = p.parseBranchSelector(selector)
|
ref = p.parseBranchSelector(selector)
|
||||||
if len(ref) > 0 {
|
if len(ref) > 0 {
|
||||||
ref = p.truncateBranch(ref)
|
ref = p.formatBranch(ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Selector = fmt.Sprintf("%s%s", p.props.GetString(BranchIcon, "\uE0A0"), ref)
|
p.Selector = fmt.Sprintf("%s%s", p.props.GetString(BranchIcon, "\uE0A0"), ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,5 +93,5 @@ func (g *Git) parsePoshGitHEAD(head string) string {
|
||||||
return fmt.Sprintf("%s%s", g.props.GetString(TagIcon, "\uF412"), head)
|
return fmt.Sprintf("%s%s", g.props.GetString(TagIcon, "\uF412"), head)
|
||||||
}
|
}
|
||||||
// regular branch
|
// regular branch
|
||||||
return fmt.Sprintf("%s%s", g.props.GetString(BranchIcon, "\uE0A0"), g.formatHEAD(head))
|
return fmt.Sprintf("%s%s", g.props.GetString(BranchIcon, "\uE0A0"), g.formatBranch(head))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package segments
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||||
|
@ -109,21 +110,40 @@ func (s *scm) Init(props properties.Properties, env runtime.Environment) {
|
||||||
s.env = env
|
s.env = env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scm) truncateBranch(branch string) string {
|
func (s *scm) formatBranch(branch string) string {
|
||||||
fullBranchPath := s.props.GetBool(FullBranchPath, true)
|
mappedBranches := s.props.GetKeyValueMap(MappedBranches, make(map[string]string))
|
||||||
maxLength := s.props.GetInt(BranchMaxLength, 0)
|
for key, value := range mappedBranches {
|
||||||
|
matchSubFolders := strings.HasSuffix(key, "*")
|
||||||
|
|
||||||
|
if matchSubFolders && len(key) > 1 {
|
||||||
|
key = key[0 : len(key)-1] // remove trailing /* or \*
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(branch, key) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
branch = strings.Replace(branch, key, value, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fullBranchPath := s.props.GetBool(FullBranchPath, true)
|
||||||
if !fullBranchPath && strings.Contains(branch, "/") {
|
if !fullBranchPath && strings.Contains(branch, "/") {
|
||||||
index := strings.LastIndex(branch, "/")
|
index := strings.LastIndex(branch, "/")
|
||||||
branch = branch[index+1:]
|
branch = branch[index+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maxLength := s.props.GetInt(BranchMaxLength, 0)
|
||||||
if maxLength == 0 || len(branch) <= maxLength {
|
if maxLength == 0 || len(branch) <= maxLength {
|
||||||
return branch
|
return branch
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol := s.props.GetString(TruncateSymbol, "")
|
truncateSymbol := s.props.GetString(TruncateSymbol, "")
|
||||||
return branch[0:maxLength] + symbol
|
lenTruncateSymbol := utf8.RuneCountInString(truncateSymbol)
|
||||||
|
maxLength -= lenTruncateSymbol
|
||||||
|
|
||||||
|
runes := []rune(branch)
|
||||||
|
return string(runes[0:maxLength]) + truncateSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scm) shouldIgnoreRootRepository(rootDir string) bool {
|
func (s *scm) shouldIgnoreRootRepository(rootDir string) bool {
|
||||||
|
|
|
@ -105,78 +105,6 @@ func TestScmStatusString(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTruncateBranch(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Case string
|
|
||||||
Expected string
|
|
||||||
Branch string
|
|
||||||
FullBranch bool
|
|
||||||
MaxLength any
|
|
||||||
}{
|
|
||||||
{Case: "No limit", Expected: "are-belong-to-us", Branch: "/all-your-base/are-belong-to-us", FullBranch: false},
|
|
||||||
{Case: "No limit - larger", Expected: "are-belong", Branch: "/all-your-base/are-belong-to-us", FullBranch: false, MaxLength: 10.0},
|
|
||||||
{Case: "No limit - smaller", Expected: "all-your-base", Branch: "/all-your-base", FullBranch: false, MaxLength: 13.0},
|
|
||||||
{Case: "Invalid setting", Expected: "all-your-base", Branch: "/all-your-base", FullBranch: false, MaxLength: "burp"},
|
|
||||||
{Case: "Lower than limit", Expected: "all-your-base", Branch: "/all-your-base", FullBranch: false, MaxLength: 20.0},
|
|
||||||
|
|
||||||
{Case: "No limit - full branch", Expected: "/all-your-base/are-belong-to-us", Branch: "/all-your-base/are-belong-to-us", FullBranch: true},
|
|
||||||
{Case: "No limit - larger - full branch", Expected: "/all-your-base", Branch: "/all-your-base/are-belong-to-us", FullBranch: true, MaxLength: 14.0},
|
|
||||||
{Case: "No limit - smaller - full branch ", Expected: "/all-your-base", Branch: "/all-your-base", FullBranch: true, MaxLength: 14.0},
|
|
||||||
{Case: "Invalid setting - full branch", Expected: "/all-your-base", Branch: "/all-your-base", FullBranch: true, MaxLength: "burp"},
|
|
||||||
{Case: "Lower than limit - full branch", Expected: "/all-your-base", Branch: "/all-your-base", FullBranch: true, MaxLength: 20.0},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
props := properties.Map{
|
|
||||||
BranchMaxLength: tc.MaxLength,
|
|
||||||
FullBranchPath: tc.FullBranch,
|
|
||||||
}
|
|
||||||
p := &Plastic{
|
|
||||||
scm: scm{
|
|
||||||
props: props,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Equal(t, tc.Expected, p.truncateBranch(tc.Branch), tc.Case)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTruncateBranchWithSymbol(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Case string
|
|
||||||
Expected string
|
|
||||||
Branch string
|
|
||||||
FullBranch bool
|
|
||||||
MaxLength any
|
|
||||||
TruncateSymbol any
|
|
||||||
}{
|
|
||||||
{Case: "No limit", Expected: "are-belong-to-us", Branch: "/all-your-base/are-belong-to-us", FullBranch: false, TruncateSymbol: "..."},
|
|
||||||
{Case: "No limit - larger", Expected: "are-belong...", Branch: "/all-your-base/are-belong-to-us", FullBranch: false, MaxLength: 10.0, TruncateSymbol: "..."},
|
|
||||||
{Case: "No limit - smaller", Expected: "all-your-base", Branch: "/all-your-base", FullBranch: false, MaxLength: 13.0, TruncateSymbol: "..."},
|
|
||||||
{Case: "Invalid setting", Expected: "all-your-base", Branch: "/all-your-base", FullBranch: false, MaxLength: "burp", TruncateSymbol: "..."},
|
|
||||||
{Case: "Lower than limit", Expected: "all-your-base", Branch: "/all-your-base", FullBranch: false, MaxLength: 20.0, TruncateSymbol: "..."},
|
|
||||||
|
|
||||||
{Case: "No limit - full branch", Expected: "/all-your-base/are-belong-to-us", Branch: "/all-your-base/are-belong-to-us", FullBranch: true, TruncateSymbol: "..."},
|
|
||||||
{Case: "No limit - larger - full branch", Expected: "/all-your-base...", Branch: "/all-your-base/are-belong-to-us", FullBranch: true, MaxLength: 14.0, TruncateSymbol: "..."},
|
|
||||||
{Case: "No limit - smaller - full branch ", Expected: "/all-your-base", Branch: "/all-your-base", FullBranch: true, MaxLength: 14.0, TruncateSymbol: "..."},
|
|
||||||
{Case: "Invalid setting - full branch", Expected: "/all-your-base", Branch: "/all-your-base", FullBranch: true, MaxLength: "burp", TruncateSymbol: "..."},
|
|
||||||
{Case: "Lower than limit - full branch", Expected: "/all-your-base", Branch: "/all-your-base", FullBranch: true, MaxLength: 20.0, TruncateSymbol: "..."},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
props := properties.Map{
|
|
||||||
BranchMaxLength: tc.MaxLength,
|
|
||||||
TruncateSymbol: tc.TruncateSymbol,
|
|
||||||
FullBranchPath: tc.FullBranch,
|
|
||||||
}
|
|
||||||
p := &Plastic{
|
|
||||||
scm: scm{
|
|
||||||
props: props,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Equal(t, tc.Expected, p.truncateBranch(tc.Branch), tc.Case)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasCommand(t *testing.T) {
|
func TestHasCommand(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Case string
|
Case string
|
||||||
|
@ -212,3 +140,90 @@ func TestHasCommand(t *testing.T) {
|
||||||
assert.Equal(t, tc.ExpectedCommand, s.command, tc.Case)
|
assert.Equal(t, tc.ExpectedCommand, s.command, tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFormatBranch(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
Expected string
|
||||||
|
Input string
|
||||||
|
MappedBranches map[string]string
|
||||||
|
BranchMaxLength int
|
||||||
|
TruncateSymbol string
|
||||||
|
NoFullBranchPath bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Case: "No settings",
|
||||||
|
Input: "main",
|
||||||
|
Expected: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "BranchMaxLength higher than branch name",
|
||||||
|
Input: "main",
|
||||||
|
Expected: "main",
|
||||||
|
BranchMaxLength: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "BranchMaxLength lower than branch name",
|
||||||
|
Input: "feature/test-this-branch",
|
||||||
|
Expected: "featu",
|
||||||
|
BranchMaxLength: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "BranchMaxLength lower than branch name, with truncate symbol",
|
||||||
|
Input: "feature/test-this-branch",
|
||||||
|
Expected: "feat…",
|
||||||
|
BranchMaxLength: 5,
|
||||||
|
TruncateSymbol: "…",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "BranchMaxLength lower than branch name, with truncate symbol and no FullBranchPath",
|
||||||
|
Input: "feature/test-this-branch",
|
||||||
|
Expected: "test…",
|
||||||
|
BranchMaxLength: 5,
|
||||||
|
TruncateSymbol: "…",
|
||||||
|
NoFullBranchPath: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "BranchMaxLength lower to branch name, with truncate symbol",
|
||||||
|
Input: "feat",
|
||||||
|
Expected: "feat",
|
||||||
|
BranchMaxLength: 5,
|
||||||
|
TruncateSymbol: "…",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Branch mapping, no BranchMaxLength",
|
||||||
|
Input: "feat/my-new-feature",
|
||||||
|
Expected: "🚀 my-new-feature",
|
||||||
|
MappedBranches: map[string]string{
|
||||||
|
"feat/*": "🚀 ",
|
||||||
|
"bug/*": "🐛 ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Branch mapping, with BranchMaxLength",
|
||||||
|
Input: "feat/my-new-feature",
|
||||||
|
Expected: "🚀 my-",
|
||||||
|
BranchMaxLength: 5,
|
||||||
|
MappedBranches: map[string]string{
|
||||||
|
"feat/*": "🚀 ",
|
||||||
|
"bug/*": "🐛 ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
g := &Git{
|
||||||
|
scm: scm{
|
||||||
|
props: properties.Map{
|
||||||
|
MappedBranches: tc.MappedBranches,
|
||||||
|
BranchMaxLength: tc.BranchMaxLength,
|
||||||
|
TruncateSymbol: tc.TruncateSymbol,
|
||||||
|
FullBranchPath: !tc.NoFullBranchPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
got := g.formatBranch(tc.Input)
|
||||||
|
assert.Equal(t, tc.Expected, got, tc.Case)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,18 +4,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/color"
|
"github.com/jandedobbeleer/oh-my-posh/src/color"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
"github.com/mattn/go-runewidth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
runewidth.DefaultCondition.EastAsianWidth = false
|
|
||||||
}
|
|
||||||
|
|
||||||
type style struct {
|
type style struct {
|
||||||
AnchorStart string
|
AnchorStart string
|
||||||
AnchorEnd string
|
AnchorEnd string
|
||||||
|
@ -400,7 +396,7 @@ func write(s rune) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
length += runewidth.RuneWidth(s)
|
length += utf8.RuneCountInString(string(s))
|
||||||
lastRune = s
|
lastRune = s
|
||||||
builder.WriteRune(s)
|
builder.WriteRune(s)
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,9 +144,15 @@
|
||||||
"full_branch_path": {
|
"full_branch_path": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"title": "Full branch path",
|
"title": "Full branch path",
|
||||||
"description": "display the full branch path instead of only the branch name",
|
"description": "display the full branch path instead of only the last part (e.g. feature/branch instead of branch)",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
|
"mapped_branches": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "Mapped Branches",
|
||||||
|
"description": "Custom glyph/text for specific branches",
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
"extra_prompt": {
|
"extra_prompt": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
|
@ -1467,6 +1473,12 @@
|
||||||
"title": "Status string formats",
|
"title": "Status string formats",
|
||||||
"description": "a key, value map representing the remote URL (or a part of that URL) and icon to use in case the upstream URL contains the key. These get precedence over the standard icons",
|
"description": "a key, value map representing the remote URL (or a part of that URL) and icon to use in case the upstream URL contains the key. These get precedence over the standard icons",
|
||||||
"default": {}
|
"default": {}
|
||||||
|
},
|
||||||
|
"mapped_branches": {
|
||||||
|
"$ref": "#/definitions/mapped_branches"
|
||||||
|
},
|
||||||
|
"full_branch_path": {
|
||||||
|
"$ref": "#/definitions/full_branch_path"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3655,6 +3667,9 @@
|
||||||
},
|
},
|
||||||
"native_fallback": {
|
"native_fallback": {
|
||||||
"$ref": "#/definitions/native_fallback"
|
"$ref": "#/definitions/native_fallback"
|
||||||
|
},
|
||||||
|
"mapped_branches": {
|
||||||
|
"$ref": "#/definitions/mapped_branches"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,26 +9,6 @@ sidebar_label: Git
|
||||||
Display git information when in a git repository. Also works for subfolders. For maximum compatibility,
|
Display git information when in a git repository. Also works for subfolders. For maximum compatibility,
|
||||||
make sure your `git` executable is up-to-date (when branch or status information is incorrect for example).
|
make sure your `git` executable is up-to-date (when branch or status information is incorrect for example).
|
||||||
|
|
||||||
:::tip
|
|
||||||
If you want to display the default [posh-git][poshgit] output, **do not** use this segment
|
|
||||||
but add the following snippet after initializing Oh My Posh in your `$PROFILE`:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
function Set-PoshGitStatus {
|
|
||||||
$global:GitStatus = Get-GitStatus
|
|
||||||
$env:POSH_GIT_STRING = Write-GitStatus -Status $global:GitStatus
|
|
||||||
}
|
|
||||||
New-Alias -Name 'Set-PoshContext' -Value 'Set-PoshGitStatus' -Scope Global -Force
|
|
||||||
```
|
|
||||||
|
|
||||||
You can then use the `POSH_GIT_STRING` environment variable in a [text segment][text]:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"template": "{{ if .Env.POSH_GIT_STRING }} {{ .Env.POSH_GIT_STRING }} {{ end }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Sample Configuration
|
## Sample Configuration
|
||||||
|
|
||||||
import Config from "@site/src/components/Config.js";
|
import Config from "@site/src/components/Config.js";
|
||||||
|
@ -55,6 +35,10 @@ import Config from "@site/src/components/Config.js";
|
||||||
"/Users/user/Projects/oh-my-posh/": "no",
|
"/Users/user/Projects/oh-my-posh/": "no",
|
||||||
},
|
},
|
||||||
source: "cli",
|
source: "cli",
|
||||||
|
mapped_branches: {
|
||||||
|
"feat/*": "🚀 ",
|
||||||
|
"bug/*": "🐛 ",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -78,6 +62,8 @@ You can set the following properties to `true` to enable fetching additional inf
|
||||||
| `fetch_user` | [`User`](#user) | `false` | fetch the current configured user for the repository |
|
| `fetch_user` | [`User`](#user) | `false` | fetch the current configured user for the repository |
|
||||||
| `status_formats` | `map[string]string` | | a key, value map allowing to override how individual status items are displayed. For example, `"status_formats": { "Added": "Added: %d" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides. |
|
| `status_formats` | `map[string]string` | | a key, value map allowing to override how individual status items are displayed. For example, `"status_formats": { "Added": "Added: %d" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides. |
|
||||||
| `source` | `string` | `cli` | <ul><li>`cli`: fetch the information using the git CLI</li><li>`pwsh`: fetch the information from the [posh-git][poshgit] PowerShell Module</li></ul> |
|
| `source` | `string` | `cli` | <ul><li>`cli`: fetch the information using the git CLI</li><li>`pwsh`: fetch the information from the [posh-git][poshgit] PowerShell Module</li></ul> |
|
||||||
|
| `mapped_branches` | `object` | | custom glyph/text for specific branches. You can use `*` at the end as a wildcard character for matching |
|
||||||
|
| `full_branch_path` | `bool` | `true` | display the full branch path instead of only the last part (e.g. `feature/branch` instead of `branch`) |
|
||||||
|
|
||||||
### Icons
|
### Icons
|
||||||
|
|
||||||
|
@ -197,11 +183,30 @@ Local changes use the following syntax:
|
||||||
| `.Name` | `string` | the user's name |
|
| `.Name` | `string` | the user's name |
|
||||||
| `.Email` | `string` | the user's email |
|
| `.Email` | `string` | the user's email |
|
||||||
|
|
||||||
|
## posh-git
|
||||||
|
|
||||||
|
If you want to display the default [posh-git][poshgit] output, **do not** use this segment
|
||||||
|
but add the following snippet after initializing Oh My Posh in your `$PROFILE`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
function Set-PoshGitStatus {
|
||||||
|
$global:GitStatus = Get-GitStatus
|
||||||
|
$env:POSH_GIT_STRING = Write-GitStatus -Status $global:GitStatus
|
||||||
|
}
|
||||||
|
New-Alias -Name 'Set-PoshContext' -Value 'Set-PoshGitStatus' -Scope Global -Force
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then use the `POSH_GIT_STRING` environment variable in a [text segment][text]:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"template": "{{ if .Env.POSH_GIT_STRING }} {{ .Env.POSH_GIT_STRING }} {{ end }}"
|
||||||
|
```
|
||||||
|
|
||||||
[poshgit]: https://github.com/dahlbyk/posh-git
|
[poshgit]: https://github.com/dahlbyk/posh-git
|
||||||
[templates]: /docs/configuration/templates
|
[templates]: /docs/configuration/templates
|
||||||
[hyperlinks]: /docs/configuration/templates#custom
|
[hyperlinks]: /docs/configuration/templates#custom
|
||||||
[untracked]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---untracked-filesltmodegt
|
[untracked]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---untracked-filesltmodegt
|
||||||
[submodules]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignore-submodulesltwhengt
|
[submodules]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignore-submodulesltwhengt
|
||||||
[kraken-ref]: https://www.gitkraken.com/invite/nQmDPR9D
|
[kraken-ref]: https://www.gitkraken.com/invite/nQmDPR9D
|
||||||
[text]: text.mdx
|
[text]: /docs/segments/system/text
|
||||||
[exclude_folders]: /docs/configuration/segment#include--exclude-folders
|
[exclude_folders]: /docs/configuration/segment#include--exclude-folders
|
||||||
|
|
|
@ -50,25 +50,26 @@ by leaving a like!
|
||||||
As doing multiple `cm` calls can slow down the prompt experience, we do not fetch information by default.
|
As doing multiple `cm` calls can slow down the prompt experience, we do not fetch information by default.
|
||||||
You can set the following property to `true` to enable fetching additional information (and populate the template).
|
You can set the following property to `true` to enable fetching additional information (and populate the template).
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ---------------- | :-----------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------- | :-----------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `fetch_status` | `boolean` | `false` | fetch the local changes |
|
| `fetch_status` | `boolean` | `false` | fetch the local changes |
|
||||||
| `status_formats` | `map[string]string` | | a key, value map allowing to override how individual status items are displayed. For example, `"status_formats": { "Added": "Added: %d" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |
|
| `status_formats` | `map[string]string` | | a key, value map allowing to override how individual status items are displayed. For example, `"status_formats": { "Added": "Added: %d" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |
|
||||||
|
|
||||||
### Icons
|
### Icons
|
||||||
|
|
||||||
#### Branch
|
#### Branch
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ------------------- | :------: | :------: | -------------------------------------------------------------------------- |
|
| ------------------- | :------: | :------: | -------------------------------------------------------------------------------------------------------- |
|
||||||
| `branch_icon` | `string` | `\uE0A0` | the icon to use in front of the git branch name |
|
| `branch_icon` | `string` | `\uE0A0` | the icon to use in front of the git branch name |
|
||||||
| `full_branch_path` | `bool` | `true` | display the full branch path: `_/main/fix-001_` instead of `_fix-001_` |
|
| `full_branch_path` | `bool` | `true` | display the full branch path instead of only the last part (e.g. `feature/branch` instead of `branch`) |
|
||||||
| `branch_max_length` | `int` | `0` | the max length for the displayed branch name where `0` implies full length |
|
| `branch_max_length` | `int` | `0` | the max length for the displayed branch name where `0` implies full length |
|
||||||
| `truncate_symbol` | `string` | | the icon to display when a branch name is truncated |
|
| `truncate_symbol` | `string` | | the icon to display when a branch name is truncated |
|
||||||
|
| `mapped_branches` | `object` | | custom glyph/text for specific branches. You can use `*` at the end as a wildcard character for matching |
|
||||||
|
|
||||||
#### Selector
|
#### Selector
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ------------- | :------: | :------: | -------------------------------------------------------------- |
|
| ------------- | :------: | :------: | -------------------------------------------------------------- |
|
||||||
| `commit_icon` | `string` | `\uF417` | icon/text to display before the commit context (detached HEAD) |
|
| `commit_icon` | `string` | `\uF417` | icon/text to display before the commit context (detached HEAD) |
|
||||||
| `tag_icon` | `string` | `\uF412` | icon/text to display before the tag context |
|
| `tag_icon` | `string` | `\uF412` | icon/text to display before the tag context |
|
||||||
|
@ -85,11 +86,11 @@ You can set the following property to `true` to enable fetching additional infor
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| --------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `.Selector` | `string` | the current selector context (branch/changeset/label) |
|
| `.Selector` | `string` | the current selector context (branch/changeset/label) |
|
||||||
| `.Behind` | `bool` | the current workspace is behind and changes are incoming |
|
| `.Behind` | `bool` | the current workspace is behind and changes are incoming |
|
||||||
| `.Status` | `Status` | changes in the workspace (see below) |
|
| `.Status` | `Status` | changes in the workspace (see below) |
|
||||||
| `.MergePending` | `bool` | if a merge is pending and needs to be committed (known issue: when no file is left after a _Change/Delete conflict_ merge, the `MergePending` property is not set) |
|
| `.MergePending` | `bool` | if a merge is pending and needs to be committed (known issue: when no file is left after a _Change/Delete conflict_ merge, the `MergePending` property is not set) |
|
||||||
|
|
||||||
### Status
|
### Status
|
||||||
|
|
Loading…
Reference in a new issue