feat(git): enable posh-git from the git segment config

BREAKING CHANGE: To use the posh-git module output, you must now set the
`source` property to `pwsh` in the git segment configuration.

In case you are using the default configuration,
you don't need to change anything.
This commit is contained in:
Jan De Dobbeleer 2024-07-26 07:17:18 +02:00 committed by Jan De Dobbeleer
parent 15ab7783b7
commit 7081cac3a2
5 changed files with 51 additions and 32 deletions

View file

@ -124,6 +124,13 @@ func (cfg *Config) Features() shell.Features {
feats = append(feats, shell.Azure) feats = append(feats, shell.Azure)
} }
} }
if segment.Type == GIT {
source := segment.Properties.GetString(segments.Source, segments.Cli)
if source == segments.Pwsh {
feats = append(feats, shell.PoshGit)
}
}
} }
} }

View file

@ -179,7 +179,8 @@ func (g *Git) Enabled() bool {
return true return true
} }
if g.hasPoshGitStatus() { source := g.props.GetString(Source, Cli)
if source == Pwsh && g.hasPoshGitStatus() {
return true return true
} }

View file

@ -36,6 +36,7 @@ func (s *GitStatus) parsePoshGitStatus(p *poshGitStatus) {
if p == nil { if p == nil {
return return
} }
s.Added = len(p.Added) s.Added = len(p.Added)
s.Deleted = len(p.Deleted) s.Deleted = len(p.Deleted)
s.Modified = len(p.Modified) s.Modified = len(p.Modified)
@ -45,13 +46,17 @@ func (s *GitStatus) parsePoshGitStatus(p *poshGitStatus) {
func (g *Git) hasPoshGitStatus() bool { func (g *Git) hasPoshGitStatus() bool {
envStatus := g.env.Getenv(poshGitEnv) envStatus := g.env.Getenv(poshGitEnv)
if len(envStatus) == 0 { if len(envStatus) == 0 {
g.env.Error(fmt.Errorf("%s environment variable not set, do you have the posh-git module installed?", poshGitEnv))
return false return false
} }
var posh poshGit var posh poshGit
err := json.Unmarshal([]byte(envStatus), &posh) err := json.Unmarshal([]byte(envStatus), &posh)
if err != nil { if err != nil {
g.env.Error(err)
return false return false
} }
g.setDir(posh.GitDir) g.setDir(posh.GitDir)
g.Working = &GitStatus{} g.Working = &GitStatus{}
g.Working.parsePoshGitStatus(posh.Working) g.Working.parsePoshGitStatus(posh.Working)
@ -63,10 +68,13 @@ func (g *Git) hasPoshGitStatus() bool {
g.Behind = posh.BehindBy g.Behind = posh.BehindBy
g.UpstreamGone = len(posh.Upstream) == 0 g.UpstreamGone = len(posh.Upstream) == 0
g.Upstream = posh.Upstream g.Upstream = posh.Upstream
g.setBranchStatus() g.setBranchStatus()
if len(g.Upstream) != 0 && g.props.GetBool(FetchUpstreamIcon, false) { if len(g.Upstream) != 0 && g.props.GetBool(FetchUpstreamIcon, false) {
g.UpstreamIcon = g.getUpstreamIcon() g.UpstreamIcon = g.getUpstreamIcon()
} }
g.poshgit = true g.poshgit = true
return true return true
} }

View file

@ -8,6 +8,7 @@ import (
"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock" "github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
testify_ "github.com/stretchr/testify/mock"
) )
func TestPoshGitSegment(t *testing.T) { func TestPoshGitSegment(t *testing.T) {
@ -186,8 +187,10 @@ func TestPoshGitSegment(t *testing.T) {
env.On("Getenv", poshGitEnv).Return(tc.PoshGitJSON) env.On("Getenv", poshGitEnv).Return(tc.PoshGitJSON)
env.On("Home").Return("/Users/bill") env.On("Home").Return("/Users/bill")
env.On("GOOS").Return(runtime.LINUX) env.On("GOOS").Return(runtime.LINUX)
env.On("Error", testify_.Anything)
env.On("RunCommand", "git", []string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false", env.On("RunCommand", "git", []string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false",
"-c", "color.status=false", "remote", "get-url", "origin"}).Return("github.com/cli", nil) "-c", "color.status=false", "remote", "get-url", "origin"}).Return("github.com/cli", nil)
g := &Git{ g := &Git{
scm: scm{ scm: scm{
env: env, env: env,
@ -197,9 +200,11 @@ func TestPoshGitSegment(t *testing.T) {
command: GITCOMMAND, command: GITCOMMAND,
}, },
} }
if len(tc.Template) == 0 { if len(tc.Template) == 0 {
tc.Template = g.Template() tc.Template = g.Template()
} }
assert.Equal(t, tc.ExpectedEnabled, g.hasPoshGitStatus(), tc.Case) assert.Equal(t, tc.ExpectedEnabled, g.hasPoshGitStatus(), tc.Case)
if tc.ExpectedEnabled { if tc.ExpectedEnabled {
assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, g), tc.Case) assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, g), tc.Case)

View file

@ -10,12 +10,8 @@ Display git information when in a git repository. Also works for subfolders. For
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 :::tip
PowerShell offers support for the [posh-git][poshgit] module for autocompletion, but it is disabled by default. If you want to display the default [posh-git][poshgit] output, **do not** use this segment
To enable this, set `$env:POSH_GIT_ENABLED = $true` in your `$PROFILE` after initializing Oh My Posh. but add the following snippet after initializing Oh My Posh in your `$PROFILE`:
This will also make use of the [posh-git][poshgit] output rather than do additional work to get the git status.
If you want to display the default [posh-git][poshgit] output, **do not** set the above environment variable
and add the following snippet after initializing Oh My Posh in your `$PROFILE`:
```powershell ```powershell
function Set-PoshGitStatus { function Set-PoshGitStatus {
@ -58,6 +54,7 @@ import Config from "@site/src/components/Config.js";
untracked_modes: { untracked_modes: {
"/Users/user/Projects/oh-my-posh/": "no", "/Users/user/Projects/oh-my-posh/": "no",
}, },
source: "cli",
}, },
}} }}
/> />
@ -69,35 +66,36 @@ import Config from "@site/src/components/Config.js";
As doing multiple git calls can slow down the prompt experience, we do not fetch information by default. As doing multiple git calls can slow down the prompt experience, we do not fetch information by default.
You can set the following properties to `true` to enable fetching additional information (and populate the template). You can set the following properties 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 |
| `ignore_status` | `[]string` | | do not fetch status for these repo's. Uses the repo's root folder and same logic as the [exclude_folders][exclude_folders] property | | `ignore_status` | `[]string` | | do not fetch status for these repo's. Uses the repo's root folder and same logic as the [exclude_folders][exclude_folders] property |
| `fetch_upstream_icon` | `boolean` | `false` | fetch upstream icon | | `fetch_upstream_icon` | `boolean` | `false` | fetch upstream icon |
| `fetch_bare_info` | `boolean` | `false` | fetch bare repo info | | `fetch_bare_info` | `boolean` | `false` | fetch bare repo info |
| `untracked_modes` | `map[string]string` | | map of repo's where to override the default [untracked files mode][untracked]:<ul><li>`no`</li><li>`normal`</li><li>`all`</li></ul>For example `"untracked_modes": { "/Users/me/repos/repo1": "no" }` - defaults to `normal` for all repo's. If you want to override for all repo's, use `*` to set the mode instead of the repo path | | `untracked_modes` | `map[string]string` | | map of repo's where to override the default [untracked files mode][untracked]:<ul><li>`no`</li><li>`normal`</li><li>`all`</li></ul>For example `"untracked_modes": { "/Users/me/repos/repo1": "no" }` - defaults to `normal` for all repo's. If you want to override for all repo's, use `*` to set the mode instead of the repo path |
| `ignore_submodules` | `map[string]string` | | map of repo's where to change the [--ignore-submodules][submodules] flag (`none`, `untracked`, `dirty` or `all`). For example `"ignore_submodules": { "/Users/me/repos/repo1": "all" }`. If you want to override for all repo's, use `*` to set the mode instead of the repo path | | `ignore_submodules` | `map[string]string` | | map of repo's where to change the [--ignore-submodules][submodules] flag (`none`, `untracked`, `dirty` or `all`). For example `"ignore_submodules": { "/Users/me/repos/repo1": "all" }`. If you want to override for all repo's, use `*` to set the mode instead of the repo path |
| `native_fallback` | `boolean` | `false` | when set to `true` and `git.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native git executable to fetch data. Not all information can be displayed in this case | | `native_fallback` | `boolean` | `false` | when set to `true` and `git.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native git executable to fetch data. Not all information can be displayed in this case |
| `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> |
### 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 |
| `branch_identical_icon` | `string` | `\u2261` | the icon to display when remote and local are identical | | `branch_identical_icon` | `string` | `\u2261` | the icon to display when remote and local are identical |
| `branch_ahead_icon` | `string` | `\u2191` | the icon to display when the local branch is ahead of its remote | | `branch_ahead_icon` | `string` | `\u2191` | the icon to display when the local branch is ahead of its remote |
| `branch_behind_icon` | `string` | `\u2193` | the icon to display when the local branch is behind its remote | | `branch_behind_icon` | `string` | `\u2193` | the icon to display when the local branch is behind its remote |
| `branch_gone_icon` | `string` | `\u2262` | the icon to display when there's no remote branch | | `branch_gone_icon` | `string` | `\u2262` | the icon to display when there's no remote 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 |
#### HEAD #### HEAD
| 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 |
@ -109,15 +107,15 @@ You can set the following properties to `true` to enable fetching additional inf
#### Upstream #### Upstream
| Name | Type | Default | Description | | Name | Type | Default | Description |
| ------------------- | :-----------------: | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------- | :-----------------: | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `github_icon` | `string` | `\uF408` | icon/text to display when the upstream is Github | | `github_icon` | `string` | `\uF408` | icon/text to display when the upstream is Github |
| `gitlab_icon` | `string` | `\uF296` | icon/text to display when the upstream is Gitlab | | `gitlab_icon` | `string` | `\uF296` | icon/text to display when the upstream is Gitlab |
| `bitbucket_icon` | `string` | `\uF171` | icon/text to display when the upstream is Bitbucket | | `bitbucket_icon` | `string` | `\uF171` | icon/text to display when the upstream is Bitbucket |
| `azure_devops_icon` | `string` | `\uEBE8` | icon/text to display when the upstream is Azure DevOps | | `azure_devops_icon` | `string` | `\uEBE8` | icon/text to display when the upstream is Azure DevOps |
| `codecommit_icon` | `string` | `\uF270` | icon/text to display when the upstream is AWS CodeCommit | | `codecommit_icon` | `string` | `\uF270` | icon/text to display when the upstream is AWS CodeCommit |
| `codeberg_icon` | `string` | `\uF330` | icon/text to display when the upstream is Codeberg | | `codeberg_icon` | `string` | `\uF330` | icon/text to display when the upstream is Codeberg |
| `git_icon` | `string` | `\uE5FB` | icon/text to display when the upstream is not known/mapped | | `git_icon` | `string` | `\uE5FB` | icon/text to display when the upstream is not known/mapped |
| `upstream_icons` | `map[string]string` | | 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 | | `upstream_icons` | `map[string]string` | | 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 |
## Template ([info][templates]) ## Template ([info][templates])
@ -158,7 +156,7 @@ You can set the following properties to `true` to enable fetching additional inf
| `.Rebase` | `boolean` | true when in a rebase | | `.Rebase` | `boolean` | true when in a rebase |
| `.CherryPick` | `boolean` | true when in a cherry pick | | `.CherryPick` | `boolean` | true when in a cherry pick |
| `.Revert` | `boolean` | true when in a revert | | `.Revert` | `boolean` | true when in a revert |
| `.LatestTag` | `string` | the latest tag name | | `.LatestTag` | `string` | the latest tag name |
### Status ### Status
@ -184,13 +182,13 @@ Local changes use the following syntax:
### Commit ### Commit
| Name | Type | Description | | Name | Type | Description |
| ------------ | ----------- | -------------------------------------- | | ------------ | ----------- | --------------------------------------- |
| `.Author` | `User` | the author of the commit (see below) | | `.Author` | `User` | the author of the commit (see below) |
| `.Committer` | `User` | the committer of the commit (see below) | | `.Committer` | `User` | the committer of the commit (see below) |
| `.Subject` | `string` | the commit subject | | `.Subject` | `string` | the commit subject |
| `.Timestamp` | `time.Time` | the commit timestamp | | `.Timestamp` | `time.Time` | the commit timestamp |
| `.Sha` | `string` | the commit SHA1 | | `.Sha` | `string` | the commit SHA1 |
### User ### User