feat(scm): allow status override

resolves #3992
This commit is contained in:
Jan De Dobbeleer 2023-06-26 08:44:17 +02:00 committed by Jan De Dobbeleer
parent e5d4282136
commit 32ee6fa7ab
15 changed files with 284 additions and 195 deletions

View file

@ -146,8 +146,9 @@ func (g *Git) Template() string {
}
func (g *Git) Enabled() bool {
g.Working = &GitStatus{}
g.Staging = &GitStatus{}
statusFormats := g.props.GetKeyValueMap(StatusFormats, map[string]string{})
g.Working = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
g.Staging = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
g.User = &User{}
if !g.shouldDisplay() {

View file

@ -51,7 +51,8 @@ func (hg *Mercurial) Enabled() bool {
return false
}
hg.Working = &MercurialStatus{}
statusFormats := hg.props.GetKeyValueMap(StatusFormats, map[string]string{})
hg.Working = &MercurialStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
displayStatus := hg.props.GetBool(FetchStatus, false)
if displayStatus {

View file

@ -165,6 +165,10 @@ A Added.File
},
}
if tc.ExpectedWorking != nil {
tc.ExpectedWorking.Formats = map[string]string{}
}
assert.True(t, hg.Enabled())
assert.Equal(t, fileInfo.Path, hg.workingDir)
assert.Equal(t, fileInfo.Path, hg.realDir)

View file

@ -61,6 +61,7 @@ func (p *Plastic) Enabled() bool {
if !wkdir.IsDir {
return false
}
p.plasticWorkspaceFolder = wkdir.ParentFolder
displayStatus := p.props.GetBool(FetchStatus, false)
p.setSelector()
@ -78,9 +79,11 @@ func (p *Plastic) setPlasticStatus() {
headChangeset := p.getHeadChangeset()
p.Behind = headChangeset > currentChangeset
statusFormats := p.props.GetKeyValueMap(StatusFormats, map[string]string{})
p.Status = &PlasticStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
// parse file state
p.MergePending = false
p.Status = &PlasticStatus{}
p.parseFilesStatus(splittedOutput)
}

View file

@ -106,7 +106,8 @@ func (sl *Sapling) setDir(dir string) {
func (sl *Sapling) setHeadContext() {
sl.setCommitContext()
sl.Working = &SaplingStatus{}
statusFormats := sl.props.GetKeyValueMap(StatusFormats, map[string]string{})
sl.Working = &SaplingStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
displayStatus := sl.props.GetBool(FetchStatus, true)
if !displayStatus {

View file

@ -11,6 +11,8 @@ import (
const (
// Fallback to native command
NativeFallback properties.Property = "native_fallback"
// Override the built-in status formats
StatusFormats properties.Property = "status_formats"
)
// ScmStatus represents part of the status of a repository
@ -25,6 +27,8 @@ type ScmStatus struct {
Clean int
Missing int
Ignored int
Formats map[string]string
}
func (s *ScmStatus) Changed() bool {
@ -41,24 +45,38 @@ func (s *ScmStatus) Changed() bool {
}
func (s *ScmStatus) String() string {
var status string
stringIfValue := func(value int, prefix string) string {
if value > 0 {
return fmt.Sprintf(" %s%d", prefix, value)
var status strings.Builder
if s.Formats == nil {
s.Formats = make(map[string]string)
}
return ""
stringIfValue := func(value int, name, prefix string) {
if value <= 0 {
return
}
status += stringIfValue(s.Untracked, "?")
status += stringIfValue(s.Added, "+")
status += stringIfValue(s.Modified, "~")
status += stringIfValue(s.Deleted, "-")
status += stringIfValue(s.Moved, ">")
status += stringIfValue(s.Unmerged, "x")
status += stringIfValue(s.Conflicted, "!")
status += stringIfValue(s.Missing, "!")
status += stringIfValue(s.Clean, "=")
status += stringIfValue(s.Ignored, "Ø")
return strings.TrimSpace(status)
// allow user override for prefix
if _, ok := s.Formats[name]; ok {
status.WriteString(fmt.Sprintf(s.Formats[name], value))
return
}
status.WriteString(fmt.Sprintf(" %s%d", prefix, value))
}
stringIfValue(s.Untracked, "Untracked", "?")
stringIfValue(s.Added, "Added", "+")
stringIfValue(s.Modified, "Modified", "~")
stringIfValue(s.Deleted, "Deleted", "-")
stringIfValue(s.Moved, "Moved", ">")
stringIfValue(s.Unmerged, "Unmerged", "x")
stringIfValue(s.Conflicted, "Conflicted", "!")
stringIfValue(s.Missing, "Missing", "!")
stringIfValue(s.Clean, "Clean", "=")
stringIfValue(s.Ignored, "Ignored", "Ø")
return strings.TrimSpace(status.String())
}
type scm struct {

View file

@ -63,27 +63,46 @@ func TestScmStatusChanged(t *testing.T) {
}
}
func TestScmStatusUnmerged(t *testing.T) {
expected := "x1"
status := &ScmStatus{
func TestScmStatusString(t *testing.T) {
cases := []struct {
Case string
Expected string
Status ScmStatus
}{
{
Case: "Unmerged",
Expected: "x1",
Status: ScmStatus{
Unmerged: 1,
}
assert.Equal(t, expected, status.String())
}
func TestScmStatusUnmergedModified(t *testing.T) {
expected := "~3 x1"
status := &ScmStatus{
},
},
{
Case: "Unmerged and Modified",
Expected: "~3 x1",
Status: ScmStatus{
Unmerged: 1,
Modified: 3,
}
assert.Equal(t, expected, status.String())
},
},
{
Case: "Empty",
Status: ScmStatus{},
},
{
Case: "Format override",
Expected: "Added: 1",
Status: ScmStatus{
Added: 1,
Formats: map[string]string{
"Added": "Added: %d",
},
},
},
}
func TestScmStatusEmpty(t *testing.T) {
expected := ""
status := &ScmStatus{}
assert.Equal(t, expected, status.String())
for _, tc := range cases {
assert.Equal(t, tc.Expected, tc.Status.String(), tc.Case)
}
}
func TestTruncateBranch(t *testing.T) {

View file

@ -63,10 +63,12 @@ func (s *Svn) shouldDisplay() bool {
if !s.hasCommand(SVNCOMMAND) {
return false
}
Svndir, err := s.env.HasParentFilePath(".svn")
if err != nil {
return false
}
if s.shouldIgnoreRootRepository(Svndir.ParentFolder) {
return false
}
@ -78,6 +80,7 @@ func (s *Svn) shouldDisplay() bool {
s.realDir = strings.TrimSuffix(s.convertToWindowsPath(Svndir.Path), "/.svn")
return true
}
// handle worktree
s.rootDir = Svndir.Path
dirPointer := strings.Trim(s.env.FileContent(Svndir.Path), " \r\n")
@ -98,7 +101,8 @@ func (s *Svn) setSvnStatus() {
s.Branch = branch[2:]
}
s.Working = &SvnStatus{}
statusFormats := s.props.GetKeyValueMap(StatusFormats, map[string]string{})
s.Working = &SvnStatus{ScmStatus: ScmStatus{Formats: statusFormats}}
displayStatus := s.props.GetBool(FetchStatus, false)
if !displayStatus {

View file

@ -193,6 +193,7 @@ R Moved.File`,
Moved: 2,
Untracked: 1,
Conflicted: 1,
Formats: map[string]string{},
}},
RefOutput: "1133",
ExpectedRef: 1133,
@ -206,18 +207,19 @@ R Moved.File`,
StatusOutput: `C build.cake`,
ExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{
Conflicted: 1,
Formats: map[string]string{},
}},
ExpectedChanged: true,
ExpectedConflicts: true,
},
{
Case: "no change",
ExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{}},
ExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{Formats: map[string]string{}}},
ExpectedChanged: false,
},
{
Case: "not an integer ref",
ExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{}},
ExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{Formats: map[string]string{}}},
ExpectedChanged: false,
RefOutput: "not an integer",
},

View file

@ -102,6 +102,12 @@
"description": "Template that creates the URL of the version info / release notes",
"default": ""
},
"status_formats": {
"type": "object",
"title": "Status string formats",
"description": "Override the status format for a specific change. Example: {\"Added\": \"Added: %d\"}",
"default": {}
},
"extra_prompt": {
"type": "object",
"default": {},
@ -1014,6 +1020,9 @@
"title": "Fetch the user",
"description": "Fetch the current configured user for the repository",
"default": false
},
"status_formats": {
"$ref": "#/definitions/status_formats"
}
}
}
@ -1891,6 +1900,9 @@
"title": "Display Status",
"description": "Display the local changes or not",
"default": true
},
"status_formats": {
"$ref": "#/definitions/status_formats"
}
}
}
@ -2371,6 +2383,9 @@
"title": "Display Status",
"description": "Display the local changes or not",
"default": true
},
"status_formats": {
"$ref": "#/definitions/status_formats"
}
}
}
@ -2584,6 +2599,9 @@
"title": "Full branch path",
"description": "display the full branch path instead of only the branch name",
"default": false
},
"status_formats": {
"$ref": "#/definitions/status_formats"
}
}
}
@ -3180,6 +3198,9 @@
"title": "Display Status",
"description": "Display the local changes or not",
"default": true
},
"status_formats": {
"$ref": "#/definitions/status_formats"
}
}
}

View file

@ -80,6 +80,7 @@ You can set the following properties to `true` to enable fetching additional inf
| `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` | 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. Defaults to `false` |
| `fetch_user` | [`User`](#user) | fetch the current configured user for the repository - defaults to `false` |
| `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. Defaults to an empty map. |
### Icons
@ -131,10 +132,10 @@ You can set the following properties to `true` to enable fetching additional inf
### Properties
| Name | Type | Description |
| ---------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- |
| ---------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `.RepoName` | `string` | the repo folder name |
| `.Working` | `GitStatus` | changes in the worktree (see below) |
| `.Staging` | `GitStatus` | staged changes in the work tree (see below) |
| `.Working` | `Status` | changes in the worktree (see below) |
| `.Staging` | `Status` | staged changes in the work tree (see below) |
| `.HEAD` | `string` | the current HEAD context (branch/rebase/merge/...) |
| `.Ref` | `string` | the current HEAD reference (branch/tag/...) |
| `.Behind` | `int` | commits behind of upstream |
@ -152,7 +153,7 @@ You can set the following properties to `true` to enable fetching additional inf
| `.Kraken` | `string` | a link to the current HEAD in [GitKraken][kraken-ref] for use in [hyperlinks][hyperlinks] in templates `{{ url .HEAD .Kraken }}` |
| `.Commit` | `Commit` | HEAD commit information (see below) |
### GitStatus
### Status
| Name | Type | Description |
| ------------ | --------- | -------------------------------------------- |
@ -164,6 +165,16 @@ You can set the following properties to `true` to enable fetching additional inf
| `.Changed` | `boolean` | if the status contains changes or not |
| `.String` | `string` | a string representation of the changes above |
Local changes use the following syntax:
| Icon | Description |
| ---- | ----------- |
| `x` | Unmerged |
| `-` | Deleted |
| `+` | Added |
| `~` | Modified |
| `?` | Untracked |
### Commit
| Name | Type | Description |
@ -180,15 +191,6 @@ You can set the following properties to `true` to enable fetching additional inf
| `.Name` | `string` | the user's name |
| `.Email` | `string` | the user's email |
Local changes use the following syntax:
| Icon | Description |
| ---- | ----------- |
| `+` | added |
| `~` | modified |
| `-` | deleted |
| `?` | untracked |
[poshgit]: https://github.com/dahlbyk/posh-git
[templates]: /docs/configuration/templates
[hyperlinks]: /docs/configuration/templates#custom

View file

@ -11,18 +11,20 @@ make sure your `hg` executable is up-to-date (when branch or status information
## Sample Configuration
import Config from '@site/src/components/Config.js';
import Config from "@site/src/components/Config.js";
<Config data={{
"type": "mercurial",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#193549",
"background": "#ffeb3b",
"properties": {
"newprop": "\uEFF1"
}
}}/>
<Config
data={{
type: "mercurial",
style: "powerline",
powerline_symbol: "\uE0B0",
foreground: "#193549",
background: "#ffeb3b",
properties: {
newprop: "\uEFF1",
},
}}
/>
## Properties
@ -32,8 +34,9 @@ As doing Mercurial (hg) calls can slow down the prompt experience, we do not fet
You can set the following properties to `true` to enable fetching additional information (and populate the template).
| Name | Type | Description |
| ----------------- | --------- | --------------------------------------------- |
| ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fetch_status` | `boolean` | fetch the local changes - defaults to `false` |
| `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. Defaults to an empty map. |
## Template ([info][templates])
@ -48,8 +51,8 @@ hg {{.Branch}} {{if .LocalCommitNumber}}({{.LocalCommitNumber}}:{{.ChangeSetIDSh
### Properties
| Name | Type | Description |
| -------------------- | ----------------- | ----------------------------------------------------- |
| `.Working` | `MercurialStatus` | changes in the worktree (see below) |
| ------------------- | ---------- | ----------------------------------------------------- |
| `.Working` | `Status` | changes in the worktree (see below) |
| `.IsTip` | `boolean` | Current commit is the tip commit |
| `.ChangeSetID` | `string` | The current local commit number |
| `.ChangeSetID` | `string` | The current local commit number |
@ -58,10 +61,10 @@ hg {{.Branch}} {{if .LocalCommitNumber}}({{.LocalCommitNumber}}:{{.ChangeSetIDSh
| `.Bookmarks` | `[]string` | the currently checked out revision number |
| `.Tags` | `[]string` | the currently checked out revision number |
### SvnStatus
### Status
| Name | Type | Description |
| --------------- | --------- | ---------------------------------------------- |
| ------------ | --------- | -------------------------------------------- |
| `.Untracked` | `int` | number of files not under version control |
| `.Modified` | `int` | number of modified files |
| `.Deleted` | `int` | number of deleted files |
@ -73,9 +76,9 @@ Local changes use the following syntax:
| Icon | Description |
| ---- | ----------- |
| `?` | untracked |
| `+` | added |
| `-` | deleted |
| `~` | modified |
| `?` | Untracked |
| `~` | Modified |
| `-` | Deleted |
| `+` | Added |
[templates]: /docs/config-templates

View file

@ -12,27 +12,30 @@ For maximum compatibility, make sure your `cm` executable is up-to-date
## Sample Configuration
import Config from '@site/src/components/Config.js';
import Config from "@site/src/components/Config.js";
<Config data={{
"type": "plastic",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#193549",
"background": "#ffeb3b",
"background_templates": [
<Config
data={{
type: "plastic",
style: "powerline",
powerline_symbol: "\uE0B0",
foreground: "#193549",
background: "#ffeb3b",
background_templates: [
"{{ if .MergePending }}#006060{{ end }}",
"{{ if .Changed }}#FF9248{{ end }}",
"{{ if and .Changed .Behind }}#ff4500{{ end }}",
"{{ if .Behind }}#B388FF{{ end }}"
"{{ if .Behind }}#B388FF{{ end }}",
],
"template": "{{ .Selector }}{{ if .Status.Changed }} \uF044 {{ end }}{{ .Status.String }}",
"properties": {
"fetch_status": true,
"branch_max_length": 25,
"truncate_symbol": "\u2026"
}
}}/>
template:
"{{ .Selector }}{{ if .Status.Changed }} \uF044 {{ end }}{{ .Status.String }}",
properties: {
fetch_status: true,
branch_max_length: 25,
truncate_symbol: "\u2026",
},
}}
/>
## Plastic SCM Icon
@ -47,7 +50,10 @@ by leaving a like!
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).
| Name | Type | Description |
| ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fetch_status` | `boolean` | fetch the local changes - defaults to `false` |
| `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. Defaults to an empty map. |
### Icons
@ -80,13 +86,13 @@ You can set the following property to `true` to enable fetching additional infor
### Properties
| Name | Type | Description |
| --------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| --------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `.Selector` | `string` | the current selector context (branch/changeset/label) |
| `.Behind` | `bool` | the current workspace is behind and changes are incoming |
| `.Status` | `PlasticStatus` | 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 commited (known issue: when no file is left after a _Change/Delete conflict_ merge, the `MergePending` property is not set) |
### PlasticStatus
### Status
| Name | Type | Description |
| ----------- | --------- | -------------------------------------------- |
@ -102,11 +108,11 @@ Local changes use the following syntax:
| Icon | Description |
| ---- | ----------- |
| `+` | added |
| `~` | modified |
| `-` | deleted |
| `v` | moved |
| `x` | unmerged |
| `x` | Unmerged |
| `-` | Deleted |
| `+` | Added |
| `~` | Modified |
| `v` | Moved |
[templates]: /docs/configuration/templates
[fa-issue]: https://github.com/FortAwesome/Font-Awesome/issues/18504

View file

@ -31,9 +31,10 @@ import Config from "@site/src/components/Config.js";
### Fetching information
| Name | Type | Description |
| ----------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fetch_status` | `boolean` | fetch the local changes - defaults to `true` |
| `native_fallback` | `boolean` | when set to `true` and `sl.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native sapling executable to fetch data. Not all information can be displayed in this case. Defaults to `false` |
| `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. Defaults to an empty map. |
## Template ([info][templates])
@ -48,9 +49,9 @@ import Config from "@site/src/components/Config.js";
### Properties
| Name | Type | Description |
| -------------- | --------------- | ------------------------------------------ |
| -------------- | --------- | ------------------------------------------ |
| `.RepoName` | `string` | the repo folder name |
| `.Working` | `SaplingStatus` | changes in the worktree (see below) |
| `.Working` | `Status` | changes in the worktree (see below) |
| `.Description` | `string` | the first line of the commit's description |
| `.Author` | `string` | the author of the commit |
| `.Hash` | `string` | the full hash of the commit |
@ -60,7 +61,7 @@ import Config from "@site/src/components/Config.js";
| `.Dir` | `string` | the repository's root directory |
| `.New` | `boolean` | true when there are no commits in the repo |
### SaplingStatus
### Status
| Name | Type | Description |
| ------------ | --------- | -------------------------------------------- |
@ -77,13 +78,13 @@ Local changes use the following syntax:
| Icon | Description |
| ---- | ----------- |
| `+` | added |
| `~` | modified |
| `-` | deleted |
| `?` | untracked |
| `=` | clean |
| `!` | missing |
| `Ø` | ignored |
| `~` | Modified |
| `+` | Added |
| `-` | Deleted |
| `?` | Untracked |
| `=` | Clean |
| `!` | Missing |
| `Ø` | Ignored |
[sapling]: https://sapling-scm.com/
[templates]: /docs/configuration/templates

View file

@ -11,18 +11,20 @@ make sure your `svn` executable is up-to-date (when branch or status information
## Sample Configuration
import Config from '@site/src/components/Config.js';
import Config from "@site/src/components/Config.js";
<Config data={{
"type": "svn",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#193549",
"background": "#ffeb3b",
"properties": {
"fetch_status": true
}
}}/>
<Config
data={{
type: "svn",
style: "powerline",
powerline_symbol: "\uE0B0",
foreground: "#193549",
background: "#ffeb3b",
properties: {
fetch_status: true,
},
}}
/>
## Properties
@ -32,9 +34,10 @@ As doing multiple [subversion][svn] calls can slow down the prompt experience, w
You can set the following properties to `true` to enable fetching additional information (and populate the template).
| Name | Type | Description |
| ----------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fetch_status` | `boolean` | fetch the local changes - defaults to `false` |
| `native_fallback` | `boolean` | when set to `true` and `svn.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native svn executable to fetch data. Not all information can be displayed in this case. Defaults to `false`. |
| `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. Defaults to an empty map. |
## Template ([info][templates])
@ -49,12 +52,12 @@ You can set the following properties to `true` to enable fetching additional inf
### Properties
| Name | Type | Description |
| ---------- | ----------- | ----------------------------------------------------- |
| `.Working` | `SvnStatus` | changes in the worktree (see below) |
| ---------- | -------- | ----------------------------------------------------- |
| `.Working` | `Status` | changes in the worktree (see below) |
| `.Branch` | `string` | current branch (releative URL reported by `svn info`) |
| `.BaseRev` | `int` | the currently checked out revision number |
### SvnStatus
### Status
| Name | Type | Description |
| --------------- | --------- | ---------------------------------------------- |
@ -72,12 +75,12 @@ Local changes use the following syntax:
| Icon | Description |
| ---- | ----------- |
| `?` | untracked |
| `+` | added |
| `!` | conflicted |
| `-` | deleted |
| `~` | modified |
| `>` | moved |
| `?` | Untracked |
| `~` | Modified |
| `-` | Deleted |
| `+` | Added |
| `>` | Moved |
| `!` | Conflicted |
[svn]: https://subversion.apache.org
[templates]: /docs/config-templates