Skip to content

Commit

Permalink
feat(posh-git): parse environment variable
Browse files Browse the repository at this point in the history
BREAKING CHANGE: this removes the posh-git segment. To mitigate,
rename the posh-git segment to git.

In case you had a custom template, make sure to migrate to the git
segment's template. You can now also leverage the same logic and
properties as the git segment in both the text template and/or
color templates.
  • Loading branch information
JanDeDobbeleer committed Sep 7, 2022
1 parent 17f75fa commit 3ded4c0
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 149 deletions.
1 change: 0 additions & 1 deletion src/engine/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error
PERL: &segments.Perl{},
PHP: &segments.Php{},
PLASTIC: &segments.Plastic{},
POSHGIT: &segments.PoshGit{},
PROJECT: &segments.Project{},
PYTHON: &segments.Python{},
R: &segments.R{},
Expand Down
116 changes: 67 additions & 49 deletions src/segments/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,34 +92,44 @@ const (
type Git struct {
scm

Working *GitStatus
Staging *GitStatus
Ahead int
Behind int
HEAD string
Ref string
Hash string
ShortHash string
BranchStatus string
Upstream string
UpstreamIcon string
UpstreamURL string
UpstreamGone bool
StashCount int
WorktreeCount int
IsWorkTree bool
RepoName string
Working *GitStatus
Staging *GitStatus
Ahead int
Behind int
HEAD string
Ref string
Hash string
ShortHash string
BranchStatus string
Upstream string
UpstreamIcon string
UpstreamURL string
RawUpstreamURL string
UpstreamGone bool
StashCount int
WorktreeCount int
IsWorkTree bool
RepoName string
}

func (g *Git) Template() string {
return " {{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}} \uF692 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \uf1bb {{ .WorktreeCount }}{{ end }} " //nolint: lll
return " {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}} \uF692 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \uf1bb {{ .WorktreeCount }}{{ end }} " //nolint: lll
}

func (g *Git) Enabled() bool {
if !g.shouldDisplay() {
return false
}

g.RepoName = environment.Base(g.env, g.convertToLinuxPath(g.realDir))
if g.props.GetBool(FetchWorktreeCount, false) {
g.WorktreeCount = g.getWorktreeContext()
}

if g.hasPoshGitStatus() {
return true
}

displayStatus := g.props.GetBool(FetchStatus, false)
if displayStatus {
g.setGitStatus()
Expand All @@ -130,22 +140,27 @@ func (g *Git) Enabled() bool {
g.Working = &GitStatus{}
g.Staging = &GitStatus{}
}
if g.Upstream != "" && g.props.GetBool(FetchUpstreamIcon, false) {
if len(g.Upstream) != 0 && g.props.GetBool(FetchUpstreamIcon, false) {
g.UpstreamIcon = g.getUpstreamIcon()
}
if g.props.GetBool(FetchStashCount, false) {
g.StashCount = g.getStashContext()
}
if g.props.GetBool(FetchWorktreeCount, false) {
g.WorktreeCount = g.getWorktreeContext()
}
return true
}

func (g *Git) Kraken() string {
root := g.getGitCommandOutput("rev-list", "--max-parents=0", "HEAD")
remote := g.getGitCommandOutput("remote", "get-url", "origin")
return fmt.Sprintf("gitkraken://repolink/%s/commit/%s?url=%s", root, g.Hash, url2.QueryEscape(remote))
if len(g.RawUpstreamURL) == 0 {
if len(g.Upstream) == 0 {
g.Upstream = "origin"
}
g.RawUpstreamURL = g.getOriginURL()
}
if len(g.Hash) == 0 {
g.Hash = g.getGitCommandOutput("rev-parse", "HEAD")
}
return fmt.Sprintf("gitkraken://repolink/%s/commit/%s?url=%s", root, g.Hash, url2.QueryEscape(g.RawUpstreamURL))
}

func (g *Git) shouldDisplay() bool {
Expand All @@ -166,12 +181,7 @@ func (g *Git) shouldDisplay() bool {
return false
}

dir := environment.ReplaceHomeDirPrefixWithTilde(g.env, gitdir.Path) // align with template PWD
if g.env.GOOS() == environment.WINDOWS {
g.Dir = strings.TrimSuffix(dir, `\.git`)
} else {
g.Dir = strings.TrimSuffix(dir, "/.git")
}
g.setDir(gitdir.Path)

if !gitdir.IsDir {
return g.hasWorktree(gitdir)
Expand All @@ -184,6 +194,15 @@ func (g *Git) shouldDisplay() bool {
return true
}

func (g *Git) setDir(dir string) {
dir = environment.ReplaceHomeDirPrefixWithTilde(g.env, dir) // align with template PWD
if g.env.GOOS() == environment.WINDOWS {
g.Dir = strings.TrimSuffix(dir, `\.git`)
return
}
g.Dir = strings.TrimSuffix(dir, "/.git")
}

func (g *Git) hasWorktree(gitdir *environment.FileInfo) bool {
g.rootDir = gitdir.Path
dirPointer := strings.Trim(g.env.FileContent(gitdir.Path), " \r\n")
Expand Down Expand Up @@ -264,8 +283,18 @@ func (g *Git) setBranchStatus() {
}

func (g *Git) getUpstreamIcon() string {
upstream := regex.ReplaceAllString("/.*", g.Upstream, "")
g.UpstreamURL = g.getOriginURL(upstream)
cleanSSHURL := func(url string) string {
if strings.HasPrefix(url, "http") {
return url
}
url = strings.TrimPrefix(url, "git://")
url = strings.TrimPrefix(url, "git@")
url = strings.TrimSuffix(url, ".git")
url = strings.ReplaceAll(url, ":", "/")
return fmt.Sprintf("https://%s", url)
}
g.RawUpstreamURL = g.getOriginURL()
g.UpstreamURL = cleanSSHURL(g.RawUpstreamURL)
if strings.Contains(g.UpstreamURL, "github") {
return g.props.GetString(GithubIcon, "\uF408 ")
}
Expand Down Expand Up @@ -539,28 +568,17 @@ func (g *Git) getWorktreeContext() int {
return count
}

func (g *Git) getOriginURL(upstream string) string {
cleanSSHURL := func(url string) string {
if strings.HasPrefix(url, "http") {
return url
}
url = strings.TrimPrefix(url, "git://")
url = strings.TrimPrefix(url, "git@")
url = strings.TrimSuffix(url, ".git")
url = strings.ReplaceAll(url, ":", "/")
return fmt.Sprintf("https://%s", url)
}
var url string
func (g *Git) getOriginURL() string {
upstream := regex.ReplaceAllString("/.*", g.Upstream, "")
cfg, err := ini.Load(g.rootDir + "/config")
if err != nil {
url = g.getGitCommandOutput("remote", "get-url", upstream)
return cleanSSHURL(url)
return g.getGitCommandOutput("remote", "get-url", upstream)
}
url = cfg.Section("remote \"" + upstream + "\"").Key("url").String()
if url == "" {
url := cfg.Section("remote \"" + upstream + "\"").Key("url").String()
if len(url) == 0 {
url = g.getGitCommandOutput("remote", "get-url", upstream)
}
return cleanSSHURL(url)
return url
}

func (g *Git) getUntrackedFilesMode() string {
Expand Down
1 change: 1 addition & 0 deletions src/segments/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func TestEnabledInWorkingDirectory(t *testing.T) {
env.On("HasParentFilePath", ".git").Return(fileInfo, nil)
env.On("PathSeparator").Return("/")
env.On("Home").Return("/Users/posh")
env.On("Getenv", poshGitEnv).Return("")
g := &Git{
scm: scm{
env: env,
Expand Down
91 changes: 73 additions & 18 deletions src/segments/posh_git.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,88 @@
package segments

import (
"oh-my-posh/environment"
"oh-my-posh/properties"
"encoding/json"
"fmt"
"strings"
)

type PoshGit struct {
props properties.Properties
env environment.Environment

Status string
}

const (
poshGitEnv = "POSH_GIT_STATUS"
)

func (p *PoshGit) Template() string {
return " {{ .Status }} "
type poshGit struct {
StashCount int `json:"StashCount"`
AheadBy int `json:"AheadBy"`
Index *poshGitStatus `json:"Index"`
RepoName string `json:"RepoName"`
HasWorking bool `json:"HasWorking"`
Branch string `json:"Branch"`
HasIndex bool `json:"HasIndex"`
GitDir string `json:"GitDir"`
BehindBy int `json:"BehindBy"`
HasUntracked bool `json:"HasUntracked"`
Working *poshGitStatus `json:"Working"`
Upstream string `json:"Upstream"`
}

type poshGitStatus struct {
Added []string `json:"Added"`
Modified []string `json:"Modified"`
Deleted []string `json:"Deleted"`
Unmerged []string `json:"Unmerged"`
}

func (s *GitStatus) parsePoshGitStatus(p *poshGitStatus) {
if p == nil {
return
}
s.Added = len(p.Added)
s.Deleted = len(p.Deleted)
s.Modified = len(p.Modified)
s.Unmerged = len(p.Unmerged)
}

func (p *PoshGit) Enabled() bool {
status := p.env.Getenv(poshGitEnv)
p.Status = strings.TrimSpace(status)
return p.Status != ""
func (g *Git) hasPoshGitStatus() bool {
envStatus := g.env.Getenv(poshGitEnv)
if len(envStatus) == 0 {
return false
}
var posh poshGit
err := json.Unmarshal([]byte(envStatus), &posh)
if err != nil {
return false
}
g.setDir(posh.GitDir)
g.Working = &GitStatus{}
g.Working.parsePoshGitStatus(posh.Working)
g.Staging = &GitStatus{}
g.Staging.parsePoshGitStatus(posh.Index)
g.HEAD = g.parsePoshGitHEAD(posh.Branch)
g.StashCount = posh.StashCount
g.Ahead = posh.AheadBy
g.Behind = posh.BehindBy
g.UpstreamGone = len(posh.Upstream) == 0
g.Upstream = posh.Upstream
g.setBranchStatus()
if len(g.Upstream) != 0 && g.props.GetBool(FetchUpstreamIcon, false) {
g.UpstreamIcon = g.getUpstreamIcon()
}
return true
}

func (p *PoshGit) Init(props properties.Properties, env environment.Environment) {
p.props = props
p.env = env
func (g *Git) parsePoshGitHEAD(head string) string {
// commit
if strings.HasSuffix(head, "...)") {
head = strings.TrimLeft(head, "(")
head = strings.TrimRight(head, ".)")
return fmt.Sprintf("%s%s", g.props.GetString(CommitIcon, "\uF417"), head)
}
// tag
if strings.HasPrefix(head, "(") {
head = strings.TrimLeft(head, "(")
head = strings.TrimRight(head, ")")
return fmt.Sprintf("%s%s", g.props.GetString(TagIcon, "\uF412"), head)
}
// regular branch
return fmt.Sprintf("%s%s", g.props.GetString(BranchIcon, "\uE0A0"), g.formatHEAD(head))
}
Loading

0 comments on commit 3ded4c0

Please sign in to comment.