From a7b01c5deb251dcf8c4071d2a11ec4b4e3bd842d Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sat, 28 Oct 2017 20:49:08 -0600 Subject: [PATCH 01/23] WIP: A simpler take at organizing settings using v5 classes --- .vscode/launch.json | 6 + src/AnsiUtils.ps1 | 24 +++ src/GitPrompt.ps1 | 473 ++++++++++++++++++++++++++++---------------- 3 files changed, 330 insertions(+), 173 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 42a031619..1b00b2b95 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,12 @@ { "version": "0.2.0", "configurations": [ + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Interactive Session", + "cwd": "${workspaceRoot}" + }, { "type": "PowerShell", "request": "launch", diff --git a/src/AnsiUtils.ps1 b/src/AnsiUtils.ps1 index 2c87f036e..b71e480ad 100644 --- a/src/AnsiUtils.ps1 +++ b/src/AnsiUtils.ps1 @@ -24,10 +24,31 @@ $AnsiEscape = [char]27 + "[" $ColorTranslatorType = 'System.Drawing.ColorTranslator' -as [Type] $ColorType = 'System.Drawing.Color' -as [Type] +function EscapseAnsiString([string]$AnsiString) { + if ($PSVersionTable.PSVersion.Major -ge 6) { + $res = $AnsiString -replace "$([char]0x1B)", '`e' + } + else { + $res = $AnsiString -replace "$([char]0x1B)", '$([char]0x1B)' + } + + $res +} + +function Test-VirtualTerminalSequece([psobject]$Object) { + if ($global:GitPromptSettings.AnsiConsole -and ($Object -is [string])) { + return $Object.Contains($AnsiEscape) + } + else { + return $false + } +} + function Get-VirtualTerminalSequence ($color, [int]$offset = 0) { if ($color -is [byte]) { return "${AnsiEscape}$(38 + $offset);5;${color}m" } + if ($color -is [String]) { try { if ($ColorTranslatorType) { @@ -41,12 +62,15 @@ function Get-VirtualTerminalSequence ($color, [int]$offset = 0) { Write-Debug $_ } } + if ($ColorType -and ($color -is $ColorType)) { return "${AnsiEscape}$(38 + $offset);2;$($color.R);$($color.G);$($color.B)m" } + if (($color -is [ConsoleColor]) -and ($color -ge 0) -and ($color -le 15)) { return "${AnsiEscape}$($ConsoleColorToAnsi[$color] + $offset)m" } + return "${AnsiEscape}$($AnsiDefaultColor + $offset)m" } diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 106b5c06c..9049ed659 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -1,101 +1,169 @@ # Inspired by Mark Embling # http://www.markembling.info/view/my-ideal-powershell-prompt-with-git-integration -$global:GitPromptSettings = [pscustomobject]@{ - DefaultForegroundColor = $null +enum BranchBehindAndAheadDisplayOptions { Full; Compact; Minimal } - BeforeText = ' [' - BeforeForegroundColor = [ConsoleColor]::Yellow - BeforeBackgroundColor = $null +class PoshGitCellColor { + [psobject]$BackgroundColor + [psobject]$ForegroundColor - DelimText = ' |' - DelimForegroundColor = [ConsoleColor]::Yellow - DelimBackgroundColor = $null + PoshGitCellColor() { + $this.ForegroundColor = $null + $this.BackgroundColor = $null + } - AfterText = ']' - AfterForegroundColor = [ConsoleColor]::Yellow - AfterBackgroundColor = $null + PoshGitCellColor([psobject]$ForegroundColor) { + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $null + } - FileAddedText = '+' - FileModifiedText = '~' - FileRemovedText = '-' - FileConflictedText = '!' + PoshGitCellColor([psobject]$ForegroundColor, [psobject]$BackgroundColor) { + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $BackgroundColor + } - LocalDefaultStatusSymbol = $null - LocalDefaultStatusForegroundColor = [ConsoleColor]::DarkGreen - LocalDefaultStatusForegroundBrightColor = [ConsoleColor]::Green - LocalDefaultStatusBackgroundColor = $null + hidden [string] ToString($color) { + $ansiTerm = "$([char]0x1b)[0m" - LocalWorkingStatusSymbol = '!' - LocalWorkingStatusForegroundColor = [ConsoleColor]::DarkRed - LocalWorkingStatusForegroundBrightColor = [ConsoleColor]::Red - LocalWorkingStatusBackgroundColor = $null + if (!$color) { + $str = "" + } + elseif (Test-VirtualTerminalSequece $color) { + $txt = EscapseAnsiString $color + $str = "${color} # ${ansiTerm} $txt" + } + else { + $str = "" - LocalStagedStatusSymbol = '~' - LocalStagedStatusForegroundColor = [ConsoleColor]::Cyan - LocalStagedStatusBackgroundColor = $null + if ($global:GitPromptSettings.AnsiConsole) { + $bg = Get-BackgroundVirtualTerminalSequence $color + $str += "${bg} ${ansiTerm} " + } - BranchUntrackedSymbol = $null - BranchForegroundColor = [ConsoleColor]::Cyan - BranchBackgroundColor = $null + $str += $color.ToString() + } - BranchGoneStatusSymbol = [char]0x00D7 # × Multiplication sign - BranchGoneStatusForegroundColor = [ConsoleColor]::DarkCyan - BranchGoneStatusBackgroundColor = $null + return $str + } - BranchIdenticalStatusToSymbol = [char]0x2261 # ≡ Three horizontal lines - BranchIdenticalStatusToForegroundColor = [ConsoleColor]::Cyan - BranchIdenticalStatusToBackgroundColor = $null + [string] ToString() { + $str = "ForegroundColor: " + $str += $this.ToString($this.ForegroundColor) + ", " + $str += "BackgroundColor: " + $str += $this.ToString($this.BackgroundColor) + return $str + } +} - BranchAheadStatusSymbol = [char]0x2191 # ↑ Up arrow - BranchAheadStatusForegroundColor = [ConsoleColor]::Green - BranchAheadStatusBackgroundColor = $null +class PoshGitTextSpan { + [string]$Text + [psobject]$BackgroundColor + [psobject]$ForegroundColor - BranchBehindStatusSymbol = [char]0x2193 # ↓ Down arrow - BranchBehindStatusForegroundColor = [ConsoleColor]::Red - BranchBehindStatusBackgroundColor = $null + PoshGitTextSpan() { + $this.Text = "" + $this.ForegroundColor = $null + $this.BackgroundColor = $null + } - BranchBehindAndAheadStatusSymbol = [char]0x2195 # ↕ Up & Down arrow - BranchBehindAndAheadStatusForegroundColor = [ConsoleColor]::Yellow - BranchBehindAndAheadStatusBackgroundColor = $null + PoshGitTextSpan([string]$Text) { + $this.Text = $Text + $this.ForegroundColor = $null + $this.BackgroundColor = $null + } - BeforeIndexText = "" - BeforeIndexForegroundColor = [ConsoleColor]::DarkGreen - BeforeIndexForegroundBrightColor = [ConsoleColor]::Green - BeforeIndexBackgroundColor = $null + PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor) { + $this.Text = $Text + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $null + } - IndexForegroundColor = [ConsoleColor]::DarkGreen - IndexForegroundBrightColor = [ConsoleColor]::Green - IndexBackgroundColor = $null + PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor, [psobject]$BackgroundColor) { + $this.Text = $Text + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $BackgroundColor + } - WorkingForegroundColor = [ConsoleColor]::DarkRed - WorkingForegroundBrightColor = [ConsoleColor]::Red - WorkingBackgroundColor = $null + PoshGitTextSpan([PoshGitTextSpan]$PoshGitTextSpan) { + $this.Text = $PoshGitTextSpan.Text + $this.ForegroundColor = $PoshGitTextSpan.ForegroundColor + $this.BackgroundColor = $PoshGitTextSpan.BackgroundColor + } - EnableStashStatus = $false - BeforeStashText = ' (' - BeforeStashBackgroundColor = $null - BeforeStashForegroundColor = [ConsoleColor]::Red - AfterStashText = ')' - AfterStashBackgroundColor = $null - AfterStashForegroundColor = [ConsoleColor]::Red - StashBackgroundColor = $null - StashForegroundColor = [ConsoleColor]::Red - - ErrorForegroundColor = [ConsoleColor]::Red - ErrorBackgroundColor = $null + PoshGitTextSpan([PoshGitCellColor]$PoshGitCellColor) { + $this.Text = '' + $this.ForegroundColor = $PoshGitCellColor.ForegroundColor + $this.BackgroundColor = $PoshGitCellColor.BackgroundColor + } - ShowStatusWhenZero = $true + [string] ToString() { + $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) + $txt = $this.RenderAnsi() + $str = "Text: '$txt',`t $($color.ToString())" + return $str + } - AutoRefreshIndex = $true + [string] RenderAnsi() { + $e = [char]27 + "[" + $txt = $this.Text + + $bg = $this.BackgroundColor + if ($bg -and !(Test-VirtualTerminalSequece $bg)) { + $bg = Get-BackgroundVirtualTerminalSequence $bg + } + + $fg = $this.ForegroundColor + if (!(Test-VirtualTerminalSequece $fg)) { + $fg = Get-ForegroundVirtualTerminalSequence $fg + } + + return "${fg}${bg}${txt}${e}0m" + } +} + +$global:GitPromptSettings = [pscustomobject]@{ + FileAddedText = '+' + FileModifiedText = '~' + FileRemovedText = '-' + FileConflictedText = '!' + + DefaultColor = [PoshGitCellColor]::new() + BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) + IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) + WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) + StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + + BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) + DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) + AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) - # Valid values are "Full", "Compact", and "Minimal" - BranchBehindAndAheadDisplay = "Full" + LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) + LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) + + BranchUntrackedSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkCyan) + + BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign + BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines + BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow + BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow + BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow + BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]"Full" + + BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + + BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) + AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) + + EnableStashStatus = $false + ShowStatusWhenZero = $true + AutoRefreshIndex = $true EnablePromptStatus = !$Global:GitMissing EnableFileStatus = $true EnableFileStatusFromCache = $null - RepositoriesInWhichToDisableFileStatus = @( ) # Array of repository paths + RepositoriesInWhichToDisableFileStatus = @() # Array of repository paths DescribeStyle = '' EnableWindowTitle = 'posh~git ~ ' @@ -114,6 +182,16 @@ $global:GitPromptSettings = [pscustomobject]@{ TruncatedBranchSuffix = '...' } +# Override some of the normal colors if the background color is set to the default DarkMagenta. +$s = $global:GitPromptSettings +if ($Host.UI.RawUI.BackgroundColor -eq [ConsoleColor]::DarkMagenta) { + $s.LocalDefaultStatusSymbol.ForegroundColor = 'Green' + $s.LocalWorkingStatusSymbol.ForegroundColor = 'Red' + $s.BeforeIndexText.ForegroundColor = 'Green' + $s.IndexColor.ForegroundColor = 'Green' + $s.WorkingColor.ForegroundColor = 'Red' +} + # PowerShell 5.x only runs on Windows so use .NET types to determine isAdminProcess # Or if we are on v6 or higher, check the $IsWindows pre-defined variable. if (($PSVersionTable.PSVersion.Major -le 5) -or $IsWindows) { @@ -128,6 +206,7 @@ else { $adminHeader = if ($isAdminProcess) { 'Administrator: ' } else { '' } $WindowTitleSupported = $true +# TODO: Hmm, this is a curious way to detemine window title supported if (Get-Module NuGet) { $WindowTitleSupported = $false } @@ -142,42 +221,72 @@ function Write-Prompt { $BackgroundColor = $null, [parameter(ValueFromPipeline = $true)] [Text.StringBuilder] - $Builder) + $Builder + ) + $s = $global:GitPromptSettings - if ($s -and ($null -eq $ForegroundColor)) { - $ForegroundColor = $s.DefaultForegroundColor + if ($s) { + if ($null -eq $ForegroundColor) { + $ForegroundColor = $s.DefaultColor.ForegroundColor + } + + if ($null -eq $BackgroundColor) { + $BackgroundColor = $s.DefaultColor.BackgroundColor + } + } + + if ($Object -is [PoshGitCellColor]) { + Write-Warning "Unexpected PoshGitCellColor passed to Write-Prompt" } if ($GitPromptSettings.AnsiConsole) { - $e = [char]27 + "[" - $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor - $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor + if ($Object -is [PoshGitTextSpan]) { + $str = $Object.RenderAnsi() + } + else { + $e = [char]27 + "[" + $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor + $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor + $str = "${f}${b}${Object}${e}0m" + } + if ($Builder) { - return $Builder.Append($f).Append($b).Append($Object).Append($e).Append("0m") + return $Builder.Append($str) } - return "${f}${b}${Object}${e}0m" + + return $str } + + if ($Object -is [PoshGitTextSpan]) { + $BackgroundColor = $Object.BackgroundColor + $ForegroundColor = $Object.ForegroundColor + $Object = $Object.Text + } + $writeHostParams = @{ Object = $Object; NoNewLine = $true; } + if (($BackgroundColor -ge 0) -and ($BackgroundColor -le 15)) { $writeHostParams.BackgroundColor = $BackgroundColor } + if (($ForegroundColor -ge 0) -and ($ForegroundColor -le 15)) { $writeHostParams.ForegroundColor = $ForegroundColor } + Write-Host @writeHostParams if ($Builder) { return $Builder } + return "" } function Format-BranchName($branchName){ $s = $global:GitPromptSettings - - if($s.BranchNameLimit -gt 0 -and $branchName.Length -gt $s.BranchNameLimit) + if (($s.BranchNameLimit -gt 0) -and ($branchName.Length -gt $s.BranchNameLimit)) { $branchName = "{0}{1}" -f $branchName.Substring(0,$s.BranchNameLimit), $s.TruncatedBranchSuffix } @@ -187,164 +296,182 @@ function Format-BranchName($branchName){ function Write-GitStatus($status) { $s = $global:GitPromptSettings - $sb = New-Object System.Text.StringBuilder + $sb = [System.Text.StringBuilder]::new(150) + + if (!$s) { + Write-Warning "`$global:GitPromptSettings is not defined. Posh-git prompt information will be limited." + } + if ($status -and $s) { - $sb | Write-Prompt $s.BeforeText -BackgroundColor $s.BeforeBackgroundColor -ForegroundColor $s.BeforeForegroundColor | Out-Null + $sb | Write-Prompt $s.BeforeText > $null - $branchStatusText = $null - $branchStatusBackgroundColor = $s.BranchBackgroundColor - $branchStatusForegroundColor = $s.BranchForegroundColor + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) if (!$status.Upstream) { - $branchStatusText = $s.BranchUntrackedSymbol - } elseif ($status.UpstreamGone -eq $true) { + $branchStatusTextSpan = $s.BranchUntrackedSymbol + } + elseif ($status.UpstreamGone -eq $true) { # Upstream branch is gone - $branchStatusText = $s.BranchGoneStatusSymbol - $branchStatusBackgroundColor = $s.BranchGoneStatusBackgroundColor - $branchStatusForegroundColor = $s.BranchGoneStatusForegroundColor - } elseif ($status.BehindBy -eq 0 -and $status.AheadBy -eq 0) { + $branchStatusTextSpan = $s.BranchGoneStatusSymbol + } + elseif (($status.BehindBy -eq 0) -and ($status.AheadBy -eq 0)) { # We are aligned with remote - $branchStatusText = $s.BranchIdenticalStatusToSymbol - $branchStatusBackgroundColor = $s.BranchIdenticalStatusToBackgroundColor - $branchStatusForegroundColor = $s.BranchIdenticalStatusToForegroundColor - } elseif ($status.BehindBy -ge 1 -and $status.AheadBy -ge 1) { + $branchStatusTextSpan = $s.BranchIdenticalStatusSymbol + } + elseif (($status.BehindBy -ge 1) -and ($status.AheadBy -ge 1)) { + $branchStatusTextSpan.ForegroundColor = $s.BranchBehindAndAheadStatusSymbol.ForegroundColor + $branchStatusTextSpan.BackgroundColor = $s.BranchBehindAndAheadStatusSymbol.BackgroundColor + # We are both behind and ahead of remote if ($s.BranchBehindAndAheadDisplay -eq "Full") { - $branchStatusText = ("{0}{1} {2}{3}" -f $s.BranchBehindStatusSymbol, $status.BehindBy, $s.BranchAheadStatusSymbol, $status.AheadBy) - } elseif ($s.BranchBehindAndAheadDisplay -eq "Compact") { - $branchStatusText = ("{0}{1}{2}" -f $status.BehindBy, $s.BranchBehindAndAheadStatusSymbol, $status.AheadBy) - } else { - $branchStatusText = $s.BranchBehindAndAheadStatusSymbol + $branchStatusTextSpan.Text = ("{0}{1} {2}{3}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy, $s.BranchAheadStatusSymbol.Text, $status.AheadBy) } - $branchStatusBackgroundColor = $s.BranchBehindAndAheadStatusBackgroundColor - $branchStatusForegroundColor = $s.BranchBehindAndAheadStatusForegroundColor - } elseif ($status.BehindBy -ge 1) { + elseif ($s.BranchBehindAndAheadDisplay -eq "Compact") { + $branchStatusTextSpan.Text = ("{0}{1}{2}" -f $status.BehindBy, $s.BranchBehindAndAheadStatusSymbol.Text, $status.AheadBy) + } + else { + $branchStatusTextSpan.Text = $s.BranchBehindAndAheadStatusSymbol.Text + } + } + elseif ($status.BehindBy -ge 1) { + $branchStatusTextSpan.ForegroundColor = $s.BranchBehindStatusSymbol.ForegroundColor + $branchStatusTextSpan.BackgroundColor = $s.BranchBehindStatusSymbol.BackgroundColor + # We are behind remote - if ($s.BranchBehindAndAheadDisplay -eq "Full" -Or $s.BranchBehindAndAheadDisplay -eq "Compact") { - $branchStatusText = ("{0}{1}" -f $s.BranchBehindStatusSymbol, $status.BehindBy) - } else { - $branchStatusText = $s.BranchBehindStatusSymbol + if (($s.BranchBehindAndAheadDisplay -eq "Full") -Or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { + $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy) + } + else { + $branchStatusTextSpan.Text = $s.BranchBehindStatusSymbol.Text } - $branchStatusBackgroundColor = $s.BranchBehindStatusBackgroundColor - $branchStatusForegroundColor = $s.BranchBehindStatusForegroundColor - } elseif ($status.AheadBy -ge 1) { + } + elseif ($status.AheadBy -ge 1) { + $branchStatusTextSpan.ForegroundColor = $s.BranchAheadStatusSymbol.ForegroundColor + $branchStatusTextSpan.BackgroundColor = $s.BranchAheadStatusSymbol.BackgroundColor + # We are ahead of remote - if ($s.BranchBehindAndAheadDisplay -eq "Full" -Or $s.BranchBehindAndAheadDisplay -eq "Compact") { - $branchStatusText = ("{0}{1}" -f $s.BranchAheadStatusSymbol, $status.AheadBy) + if (($s.BranchBehindAndAheadDisplay -eq "Full") -or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { + $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchAheadStatusSymbol.Text, $status.AheadBy) } else { - $branchStatusText = $s.BranchAheadStatusSymbol + $branchStatusTextSpan.Text = $s.BranchAheadStatusSymbol.Text } - $branchStatusBackgroundColor = $s.BranchAheadStatusBackgroundColor - $branchStatusForegroundColor = $s.BranchAheadStatusForegroundColor - } else { + } + else { # This condition should not be possible but defaulting the variables to be safe - $branchStatusText = "?" + $branchStatusTextSpan.Text = "?" } - $sb | Write-Prompt (Format-BranchName($status.Branch)) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor | Out-Null + $branchNameTextSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) + $branchNameTextSpan.Text = Format-BranchName $status.Branch + $sb | Write-Prompt $branchNameTextSpan > $null - if ($branchStatusText) { - $sb | Write-Prompt (" {0}" -f $branchStatusText) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor | Out-Null + if ($branchStatusTextSpan.Text) { + $sb.Append(' ') > $null + $sb | Write-Prompt $branchStatusTextSpan > $null } - if($s.EnableFileStatus -and $status.HasIndex) { - $sb | Write-Prompt $s.BeforeIndexText -BackgroundColor $s.BeforeIndexBackgroundColor -ForegroundColor $s.BeforeIndexForegroundColor | Out-Null + if ($s.EnableFileStatus -and $status.HasIndex) { + $sb | Write-Prompt $s.BeforeIndexText > $null - if($s.ShowStatusWhenZero -or $status.Index.Added) { - $sb | Write-Prompt (" $($s.FileAddedText)$($status.Index.Added.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null + $statusTextSpan = [PoshGitTextSpan]::new($s.IndexColor) + if ($s.ShowStatusWhenZero -or $status.Index.Added) { + $statusTextSpan.Text = " $($s.FileAddedText)$($status.Index.Added.Count)" + $sb | Write-Prompt $statusTextSpan > $null } - if($s.ShowStatusWhenZero -or $status.Index.Modified) { - $sb | Write-Prompt (" $($s.FileModifiedText)$($status.Index.Modified.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null + + if ($s.ShowStatusWhenZero -or $status.Index.Modified) { + $statusTextSpan.Text = " $($s.FileModifiedText)$($status.Index.Modified.Count)" + $sb | Write-Prompt $statusTextSpan > $null } - if($s.ShowStatusWhenZero -or $status.Index.Deleted) { - $sb | Write-Prompt (" $($s.FileRemovedText)$($status.Index.Deleted.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null + + if ($s.ShowStatusWhenZero -or $status.Index.Deleted) { + $statusTextSpan.Text = " $($s.FileRemovedText)$($status.Index.Deleted.Count)" + $sb | Write-Prompt $statusTextSpan > $null } if ($status.Index.Unmerged) { - $sb | Write-Prompt (" $($s.FileConflictedText)$($status.Index.Unmerged.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null + $statusTextSpan.Text = " $($s.FileConflictedText)$($status.Index.Unmerged.Count)" + $sb | Write-Prompt $statusTextSpan > $null } if($status.HasWorking) { - $sb | Write-Prompt $s.DelimText -BackgroundColor $s.DelimBackgroundColor -ForegroundColor $s.DelimForegroundColor | Out-Null + $sb | Write-Prompt $s.DelimText > $null } } - if($s.EnableFileStatus -and $status.HasWorking) { - if($s.ShowStatusWhenZero -or $status.Working.Added) { - $sb | Write-Prompt (" $($s.FileAddedText)$($status.Working.Added.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null + if ($s.EnableFileStatus -and $status.HasWorking) { + $workingTextSpan = [PoshGitTextSpan]::new($s.WorkingColor) + + if ($s.ShowStatusWhenZero -or $status.Working.Added) { + $workingTextSpan.Text = " $($s.FileAddedText)$($status.Working.Added.Count)" + $sb | Write-Prompt $workingTextSpan > $null } - if($s.ShowStatusWhenZero -or $status.Working.Modified) { - $sb | Write-Prompt (" $($s.FileModifiedText)$($status.Working.Modified.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null + + if ($s.ShowStatusWhenZero -or $status.Working.Modified) { + $workingTextSpan.Text = " $($s.FileModifiedText)$($status.Working.Modified.Count)" + $sb | Write-Prompt $workingTextSpan > $null } - if($s.ShowStatusWhenZero -or $status.Working.Deleted) { - $sb | Write-Prompt (" $($s.FileRemovedText)$($status.Working.Deleted.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null + + if ($s.ShowStatusWhenZero -or $status.Working.Deleted) { + $workingTextSpan.Text = " $($s.FileRemovedText)$($status.Working.Deleted.Count)" + $sb | Write-Prompt $workingTextSpan > $null } if ($status.Working.Unmerged) { - $sb | Write-Prompt (" $($s.FileConflictedText)$($status.Working.Unmerged.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null + $workingTextSpan.Text = " $($s.FileConflictedText)$($status.Working.Unmerged.Count)" + $sb | Write-Prompt $workingTextSpan > $null } } if ($status.HasWorking) { # We have un-staged files in the working tree - $localStatusSymbol = $s.LocalWorkingStatusSymbol - $localStatusBackgroundColor = $s.LocalWorkingStatusBackgroundColor - $localStatusForegroundColor = $s.LocalWorkingStatusForegroundColor - } elseif ($status.HasIndex) { + $localStatusSymbol = $s.LocalWorkingStatusSymbol + } + elseif ($status.HasIndex) { # We have staged but uncommited files - $localStatusSymbol = $s.LocalStagedStatusSymbol - $localStatusBackgroundColor = $s.LocalStagedStatusBackgroundColor - $localStatusForegroundColor = $s.LocalStagedStatusForegroundColor - } else { + $localStatusSymbol = $s.LocalStagedStatusSymbol + } + else { # No uncommited changes - $localStatusSymbol = $s.LocalDefaultStatusSymbol - $localStatusBackgroundColor = $s.LocalDefaultStatusBackgroundColor - $localStatusForegroundColor = $s.LocalDefaultStatusForegroundColor + $localStatusSymbol = $s.LocalDefaultStatusSymbol } if ($localStatusSymbol) { - $sb | Write-Prompt (" {0}" -f $localStatusSymbol) -BackgroundColor $localStatusBackgroundColor -ForegroundColor $localStatusForegroundColor | Out-Null + $sb.Append(' ') > $null + $sb | Write-Prompt $localStatusSymbol > $null } if ($s.EnableStashStatus -and ($status.StashCount -gt 0)) { - $sb | Write-Prompt $s.BeforeStashText -BackgroundColor $s.BeforeStashBackgroundColor -ForegroundColor $s.BeforeStashForegroundColor | Out-Null - $sb | Write-Prompt $status.StashCount -BackgroundColor $s.StashBackgroundColor -ForegroundColor $s.StashForegroundColor | Out-Null - $sb | Write-Prompt $s.AfterStashText -BackgroundColor $s.AfterStashBackgroundColor -ForegroundColor $s.AfterStashForegroundColor | Out-Null + $stashTextSpan = [PoshGitTextSpan]::new("$($status.StashCount)", $s.StashColor) + + $sb | Write-Prompt $s.BeforeStashText > $null + $sb | Write-Prompt $stashTextSpan > $null + $sb | Write-Prompt $s.AfterStashText > $null } - $sb | Write-Prompt $s.AfterText -BackgroundColor $s.AfterBackgroundColor -ForegroundColor $s.AfterForegroundColor | Out-Null + $sb | Write-Prompt $s.AfterText > $null if ($WindowTitleSupported -and $s.EnableWindowTitle) { - if( -not $Global:PreviousWindowTitle ) { + if (!$Global:PreviousWindowTitle) { $Global:PreviousWindowTitle = $Host.UI.RawUI.WindowTitle } + $repoName = Split-Path -Leaf (Split-Path $status.GitDir) $prefix = if ($s.EnableWindowTitle -is [string]) { $s.EnableWindowTitle } else { '' } $Host.UI.RawUI.WindowTitle = "$script:adminHeader$prefix$repoName [$($status.Branch)]" } return $sb.ToString() - } elseif ( $Global:PreviousWindowTitle ) { + } + elseif ($Global:PreviousWindowTitle) { $Host.UI.RawUI.WindowTitle = $Global:PreviousWindowTitle return "" } } -if(!(Test-Path Variable:Global:VcsPromptStatuses)) { +if (!(Test-Path Variable:Global:VcsPromptStatuses)) { $Global:VcsPromptStatuses = @() } -$s = $global:GitPromptSettings - -# Override some of the normal colors if the background color is set to the default DarkMagenta. -if ($Host.UI.RawUI.BackgroundColor -eq [ConsoleColor]::DarkMagenta) { - $s.LocalDefaultStatusForegroundColor = $s.LocalDefaultStatusForegroundBrightColor - $s.LocalWorkingStatusForegroundColor = $s.LocalWorkingStatusForegroundBrightColor - - $s.BeforeIndexForegroundColor = $s.BeforeIndexForegroundBrightColor - $s.IndexForegroundColor = $s.IndexForegroundBrightColor - - $s.WorkingForegroundColor = $s.WorkingForegroundBrightColor -} function Global:Write-VcsStatus { Set-ConsoleMode -ANSI @@ -360,9 +487,9 @@ $PoshGitVcsPrompt = { catch { $s = $Global:GitPromptSettings if ($s) { - Write-Prompt $s.BeforeText -BackgroundColor $s.BeforeBackgroundColor -ForegroundColor $s.BeforeForegroundColor - Write-Prompt "Error: $_" -BackgroundColor $s.ErrorBackgroundColor -ForegroundColor $s.ErrorForegroundColor - Write-Prompt $s.AfterText -BackgroundColor $s.AfterBackgroundColor -ForegroundColor $s.AfterForegroundColor + Write-Prompt $s.BeforeText + Write-Prompt "Error: $_" -BackgroundColor $s.ErrorColor.BackgroundColor -ForegroundColor $s.ErrorColor.ForegroundColor + Write-Prompt $s.AfterText } } } From 7460daf8c4390cc31954b77d952168fb1082daf1 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sat, 28 Oct 2017 23:10:13 -0600 Subject: [PATCH 02/23] Reorder some settings --- src/GitPrompt.ps1 | 165 ++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 85 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 9049ed659..2339ee6a2 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -37,7 +37,7 @@ class PoshGitCellColor { if ($global:GitPromptSettings.AnsiConsole) { $bg = Get-BackgroundVirtualTerminalSequence $color - $str += "${bg} ${ansiTerm} " + $str += "${bg} ${ansiTerm} " } $str += $color.ToString() @@ -122,64 +122,63 @@ class PoshGitTextSpan { } $global:GitPromptSettings = [pscustomobject]@{ - FileAddedText = '+' - FileModifiedText = '~' - FileRemovedText = '-' - FileConflictedText = '!' - - DefaultColor = [PoshGitCellColor]::new() - BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) - IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) - WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) - StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - - BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) - DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) - AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) - - LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) - LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) - - BranchUntrackedSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkCyan) - - BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign - BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines - BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow - BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow - BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow - BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]"Full" - - BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - - BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) - AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) - - EnableStashStatus = $false - ShowStatusWhenZero = $true - AutoRefreshIndex = $true - - EnablePromptStatus = !$Global:GitMissing - EnableFileStatus = $true - EnableFileStatusFromCache = $null - RepositoriesInWhichToDisableFileStatus = @() # Array of repository paths - DescribeStyle = '' - - EnableWindowTitle = 'posh~git ~ ' - - AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") - - DefaultPromptPrefix = '' - DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' - DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' - DefaultPromptEnableTiming = $false - DefaultPromptAbbreviateHomeDirectory = $false - - Debug = $false - - BranchNameLimit = 0 - TruncatedBranchSuffix = '...' + DefaultColor = [PoshGitCellColor]::new() + BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) + IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) + WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) + StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + + BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) + DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) + AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) + + LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) + LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) + + BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign + BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines + BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow + BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow + BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow + + BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) + AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) + + FileAddedText = '+' + FileModifiedText = '~' + FileRemovedText = '-' + FileConflictedText = '!' + BranchUntrackedText = '' + + BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]"Full" + + EnableStashStatus = $false + ShowStatusWhenZero = $true + AutoRefreshIndex = $true + + EnablePromptStatus = !$global:GitMissing + EnableFileStatus = $true + EnableFileStatusFromCache = $null + RepositoriesInWhichToDisableFileStatus = @() # Array of repository paths + DescribeStyle = '' + + EnableWindowTitle = 'posh~git ~ ' + + AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") + + DefaultPromptPrefix = '' + DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' + DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' + DefaultPromptEnableTiming = $false + DefaultPromptAbbreviateHomeDirectory = $false + + Debug = $false + + BranchNameLimit = 0 + TruncatedBranchSuffix = '...' } # Override some of the normal colors if the background color is set to the default DarkMagenta. @@ -213,13 +212,16 @@ if (Get-Module NuGet) { function Write-Prompt { param( - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] $Object, - [parameter()] + + [Parameter()] $ForegroundColor = $null, - [parameter()] + + [Parameter()] $BackgroundColor = $null, - [parameter(ValueFromPipeline = $true)] + + [Parameter(ValueFromPipeline = $true)] [Text.StringBuilder] $Builder ) @@ -235,10 +237,6 @@ function Write-Prompt { } } - if ($Object -is [PoshGitCellColor]) { - Write-Warning "Unexpected PoshGitCellColor passed to Write-Prompt" - } - if ($GitPromptSettings.AnsiConsole) { if ($Object -is [PoshGitTextSpan]) { $str = $Object.RenderAnsi() @@ -298,17 +296,13 @@ function Write-GitStatus($status) { $s = $global:GitPromptSettings $sb = [System.Text.StringBuilder]::new(150) - if (!$s) { - Write-Warning "`$global:GitPromptSettings is not defined. Posh-git prompt information will be limited." - } - if ($status -and $s) { $sb | Write-Prompt $s.BeforeText > $null $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) if (!$status.Upstream) { - $branchStatusTextSpan = $s.BranchUntrackedSymbol + $branchStatusTextSpan.Text = $s.BranchUntrackedText } elseif ($status.UpstreamGone -eq $true) { # Upstream branch is gone @@ -366,7 +360,7 @@ function Write-GitStatus($status) { $sb | Write-Prompt $branchNameTextSpan > $null if ($branchStatusTextSpan.Text) { - $sb.Append(' ') > $null + $branchStatusTextSpan.Text = " " + $branchStatusTextSpan.Text $sb | Write-Prompt $branchStatusTextSpan > $null } @@ -436,13 +430,14 @@ function Write-GitStatus($status) { $localStatusSymbol = $s.LocalDefaultStatusSymbol } - if ($localStatusSymbol) { - $sb.Append(' ') > $null + if ($localStatusSymbol.Text) { + $localStatusSymbol.Text = " " + $localStatusSymbol.Text $sb | Write-Prompt $localStatusSymbol > $null } if ($s.EnableStashStatus -and ($status.StashCount -gt 0)) { - $stashTextSpan = [PoshGitTextSpan]::new("$($status.StashCount)", $s.StashColor) + $stashTextSpan = [PoshGitTextSpan]::new($s.StashColor) + $stashTextSpan.Text = "$($status.StashCount)" $sb | Write-Prompt $s.BeforeStashText > $null $sb | Write-Prompt $stashTextSpan > $null @@ -452,8 +447,8 @@ function Write-GitStatus($status) { $sb | Write-Prompt $s.AfterText > $null if ($WindowTitleSupported -and $s.EnableWindowTitle) { - if (!$Global:PreviousWindowTitle) { - $Global:PreviousWindowTitle = $Host.UI.RawUI.WindowTitle + if (!$global:PreviousWindowTitle) { + $global:PreviousWindowTitle = $Host.UI.RawUI.WindowTitle } $repoName = Split-Path -Leaf (Split-Path $status.GitDir) @@ -463,29 +458,29 @@ function Write-GitStatus($status) { return $sb.ToString() } - elseif ($Global:PreviousWindowTitle) { - $Host.UI.RawUI.WindowTitle = $Global:PreviousWindowTitle + elseif ($global:PreviousWindowTitle) { + $Host.UI.RawUI.WindowTitle = $global:PreviousWindowTitle return "" } } if (!(Test-Path Variable:Global:VcsPromptStatuses)) { - $Global:VcsPromptStatuses = @() + $global:VcsPromptStatuses = @() } function Global:Write-VcsStatus { Set-ConsoleMode -ANSI - $Global:VcsPromptStatuses | ForEach-Object { & $_ } + $global:VcsPromptStatuses | ForEach-Object { & $_ } } # Add scriptblock that will execute for Write-VcsStatus $PoshGitVcsPrompt = { try { - $Global:GitStatus = Get-GitStatus + $global:GitStatus = Get-GitStatus Write-GitStatus $GitStatus } catch { - $s = $Global:GitPromptSettings + $s = $global:GitPromptSettings if ($s) { Write-Prompt $s.BeforeText Write-Prompt "Error: $_" -BackgroundColor $s.ErrorColor.BackgroundColor -ForegroundColor $s.ErrorColor.ForegroundColor @@ -494,4 +489,4 @@ $PoshGitVcsPrompt = { } } -$Global:VcsPromptStatuses += $PoshGitVcsPrompt +$global:VcsPromptStatuses += $PoshGitVcsPrompt From 98c61bb92d296fe8145a93b2518852f8e48b8fcc Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 29 Oct 2017 00:04:13 -0600 Subject: [PATCH 03/23] Make sure value is not null --- src/GitPrompt.ps1 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 2339ee6a2..ee8a34530 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -30,14 +30,14 @@ class PoshGitCellColor { } elseif (Test-VirtualTerminalSequece $color) { $txt = EscapseAnsiString $color - $str = "${color} # ${ansiTerm} $txt" + $str = "${color} #${ansiTerm} $txt" } else { $str = "" if ($global:GitPromptSettings.AnsiConsole) { $bg = Get-BackgroundVirtualTerminalSequence $color - $str += "${bg} ${ansiTerm} " + $str += "${bg} ${ansiTerm} " } $str += $color.ToString() @@ -113,7 +113,7 @@ class PoshGitTextSpan { } $fg = $this.ForegroundColor - if (!(Test-VirtualTerminalSequece $fg)) { + if ($fg -and !(Test-VirtualTerminalSequece $fg)) { $fg = Get-ForegroundVirtualTerminalSequence $fg } @@ -360,8 +360,9 @@ function Write-GitStatus($status) { $sb | Write-Prompt $branchNameTextSpan > $null if ($branchStatusTextSpan.Text) { - $branchStatusTextSpan.Text = " " + $branchStatusTextSpan.Text - $sb | Write-Prompt $branchStatusTextSpan > $null + $textSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) + $textSpan.Text = " " + $branchStatusTextSpan.Text + $sb | Write-Prompt $textSpan > $null } if ($s.EnableFileStatus -and $status.HasIndex) { @@ -431,8 +432,9 @@ function Write-GitStatus($status) { } if ($localStatusSymbol.Text) { - $localStatusSymbol.Text = " " + $localStatusSymbol.Text - $sb | Write-Prompt $localStatusSymbol > $null + $textSpan = [PoshGitTextSpan]::new($localStatusSymbol) + $textSpan.Text = " " + $localStatusSymbol.Text + $sb | Write-Prompt $textSpan > $null } if ($s.EnableStashStatus -and ($status.StashCount -gt 0)) { From b28513c70723b637bb95717f53a2b46141d6c9b0 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 29 Oct 2017 00:39:07 -0600 Subject: [PATCH 04/23] Try another approach with custom ansi --- src/GitPrompt.ps1 | 51 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index ee8a34530..0a971588f 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -24,20 +24,21 @@ class PoshGitCellColor { hidden [string] ToString($color) { $ansiTerm = "$([char]0x1b)[0m" + $colorSwatch = " " if (!$color) { $str = "" } elseif (Test-VirtualTerminalSequece $color) { $txt = EscapseAnsiString $color - $str = "${color} #${ansiTerm} $txt" + $str = "${color}${colorSwatch}${ansiTerm} $txt" } else { $str = "" if ($global:GitPromptSettings.AnsiConsole) { $bg = Get-BackgroundVirtualTerminalSequence $color - $str += "${bg} ${ansiTerm} " + $str += "${bg}${colorSwatch}${ansiTerm} " } $str += $color.ToString() @@ -59,6 +60,7 @@ class PoshGitTextSpan { [string]$Text [psobject]$BackgroundColor [psobject]$ForegroundColor + [string]$CustomAnsi PoshGitTextSpan() { $this.Text = "" @@ -97,9 +99,26 @@ class PoshGitTextSpan { } [string] ToString() { - $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) - $txt = $this.RenderAnsi() - $str = "Text: '$txt',`t $($color.ToString())" + if ($global:GitPromptSettings.AnsiConsole) { + if ($this.CustomAnsi) { + $e = [char]27 + "[" + $ansi = $this.CustomAnsi + $escAnsi = EscapseAnsiString $this.CustomAnsi + $txt = $this.RenderAnsi() + $str = "Text: '$txt',`t CustomAnsi: '${ansi}${escAnsi}${e}0m'" + } + else { + $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) + $txt = $this.RenderAnsi() + $str = "Text: '$txt',`t $($color.ToString())" + } + } + else { + $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) + $txt = $this.Text + $str = "Text: '$txt',`t $($color.ToString())" + } + return $str } @@ -107,17 +126,25 @@ class PoshGitTextSpan { $e = [char]27 + "[" $txt = $this.Text - $bg = $this.BackgroundColor - if ($bg -and !(Test-VirtualTerminalSequece $bg)) { - $bg = Get-BackgroundVirtualTerminalSequence $bg + if ($this.CustomAnsi) { + $ansi = $this.CustomAnsi + $str = "${ansi}${txt}${e}0m" } + else { + $bg = $this.BackgroundColor + if ($bg -and !(Test-VirtualTerminalSequece $bg)) { + $bg = Get-BackgroundVirtualTerminalSequence $bg + } - $fg = $this.ForegroundColor - if ($fg -and !(Test-VirtualTerminalSequece $fg)) { - $fg = Get-ForegroundVirtualTerminalSequence $fg + $fg = $this.ForegroundColor + if ($fg -and !(Test-VirtualTerminalSequece $fg)) { + $fg = Get-ForegroundVirtualTerminalSequence $fg + } + + $str = "${fg}${bg}${txt}${e}0m" } - return "${fg}${bg}${txt}${e}0m" + return $str } } From 4d8e08c1002fe2a220a9288186e6d8c26619a90b Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 29 Oct 2017 16:56:14 -0600 Subject: [PATCH 05/23] WIP - refactor Write-Prompt --- src/AnsiUtils.ps1 | 2 +- src/GitPrompt.ps1 | 198 ++++++++++++++++++++++++++++++---------------- src/posh-git.psd1 | 1 + src/posh-git.psm1 | 1 + 4 files changed, 131 insertions(+), 71 deletions(-) diff --git a/src/AnsiUtils.ps1 b/src/AnsiUtils.ps1 index b71e480ad..d5ee3a1dd 100644 --- a/src/AnsiUtils.ps1 +++ b/src/AnsiUtils.ps1 @@ -29,7 +29,7 @@ function EscapseAnsiString([string]$AnsiString) { $res = $AnsiString -replace "$([char]0x1B)", '`e' } else { - $res = $AnsiString -replace "$([char]0x1B)", '$([char]0x1B)' + $res = $AnsiString -replace "$([char]0x1B)", '$([char]27)' } $res diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 0a971588f..b0c6d1ac4 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -66,36 +66,42 @@ class PoshGitTextSpan { $this.Text = "" $this.ForegroundColor = $null $this.BackgroundColor = $null + $this.CustomAnsi = $null } PoshGitTextSpan([string]$Text) { $this.Text = $Text $this.ForegroundColor = $null $this.BackgroundColor = $null + $this.CustomAnsi = $null } PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor) { $this.Text = $Text $this.ForegroundColor = $ForegroundColor $this.BackgroundColor = $null + $this.CustomAnsi = $null } PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor, [psobject]$BackgroundColor) { $this.Text = $Text $this.ForegroundColor = $ForegroundColor $this.BackgroundColor = $BackgroundColor + $this.CustomAnsi = $null } PoshGitTextSpan([PoshGitTextSpan]$PoshGitTextSpan) { $this.Text = $PoshGitTextSpan.Text $this.ForegroundColor = $PoshGitTextSpan.ForegroundColor $this.BackgroundColor = $PoshGitTextSpan.BackgroundColor + $this.CustomAnsi = $PoshGitTextSpan.CustomAnsi } PoshGitTextSpan([PoshGitCellColor]$PoshGitCellColor) { $this.Text = '' $this.ForegroundColor = $PoshGitCellColor.ForegroundColor $this.BackgroundColor = $PoshGitCellColor.BackgroundColor + $this.CustomAnsi = $null } [string] ToString() { @@ -249,7 +255,7 @@ function Write-Prompt { $BackgroundColor = $null, [Parameter(ValueFromPipeline = $true)] - [Text.StringBuilder] + [System.Text.StringBuilder] $Builder ) @@ -262,24 +268,24 @@ function Write-Prompt { if ($null -eq $BackgroundColor) { $BackgroundColor = $s.DefaultColor.BackgroundColor } - } - if ($GitPromptSettings.AnsiConsole) { - if ($Object -is [PoshGitTextSpan]) { - $str = $Object.RenderAnsi() - } - else { - $e = [char]27 + "[" - $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor - $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor - $str = "${f}${b}${Object}${e}0m" - } + if ($s.AnsiConsole) { + if ($Object -is [PoshGitTextSpan]) { + $str = $Object.RenderAnsi() + } + else { + $e = [char]27 + "[" + $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor + $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor + $str = "${f}${b}${Object}${e}0m" + } - if ($Builder) { - return $Builder.Append($str) - } + if ($Builder) { + return $Builder.Append($str) + } - return $str + return $str + } } if ($Object -is [PoshGitTextSpan]) { @@ -293,11 +299,11 @@ function Write-Prompt { NoNewLine = $true; } - if (($BackgroundColor -ge 0) -and ($BackgroundColor -le 15)) { + if ($BackgroundColor -and ($BackgroundColor -ge 0) -and ($BackgroundColor -le 15)) { $writeHostParams.BackgroundColor = $BackgroundColor } - if (($ForegroundColor -ge 0) -and ($ForegroundColor -le 15)) { + if ($ForegroundColor -and ($ForegroundColor -ge 0) -and ($ForegroundColor -le 15)) { $writeHostParams.ForegroundColor = $ForegroundColor } @@ -319,73 +325,125 @@ function Format-BranchName($branchName){ return $branchName } -function Write-GitStatus($status) { - $s = $global:GitPromptSettings - $sb = [System.Text.StringBuilder]::new(150) +<# +.SYNOPSIS + Writes the branch status text given the current Git status. +.DESCRIPTION + Writes the branch status text given the current Git status which can retrieved + via the Get-GitStatus command. Branch status includes information about the + upstream branch, how far behind and/or ahead the local branch is from the remote. +.EXAMPLE +An example + +.OUTPUTS + System.String, System.Text.StringBuilder + This command returns a System.String object unless the -StringBuilder parameter + is supplied. In this case, it returns a System.Text.StringBuilder. +#> +function Write-BranchStatus { + [CmdletBinding(DefaultParameterSetName="Default")] + param( + # The Git status, retrieved from Get-GitStatus, from which to write the branch status. + # If no other parameters are specified, that branch status is written to the host. + [Parameter(ParameterSetName = "Default")] + [Parameter(ParameterSetName = "PoshGitTextSpan")] + [Parameter(ParameterSetName = "StringBuilder")] + [Parameter(Mandatory, Position = 0)] + [ValidateNotNull()] + $status, + + # If specified the branch status is written into the provided BranchStatusTextSpan object. + [Parameter(ParameterSetName="PoshGitTextSpan")] + [PoshGitTextSpan] + $BranchStatusTextSpan, + + # If specified the branch status is written into the provided StringBuilder object. + [Parameter(ParameterSetName = "StringBuilder", ValueFromPipeline = $true)] + [System.Text.StringBuilder] + $StringBuilder + ) - if ($status -and $s) { - $sb | Write-Prompt $s.BeforeText > $null + $s = $global:GitPromptSettings + if (!$s) { + Write-Warning "$($MyInvocation.MyCommand.Name): `$global:GitPromptSettings variable not found. No BranchStatus generated." + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } - $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) + if (!$BranchStatusTextSpan) { + $BranchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) + } - if (!$status.Upstream) { - $branchStatusTextSpan.Text = $s.BranchUntrackedText + if (!$status.Upstream) { + $branchStatusTextSpan.Text = $s.BranchUntrackedText + } + elseif ($status.UpstreamGone -eq $true) { + # Upstream branch is gone + $branchStatusTextSpan = $s.BranchGoneStatusSymbol + } + elseif (($status.BehindBy -eq 0) -and ($status.AheadBy -eq 0)) { + # We are aligned with remote + $branchStatusTextSpan = $s.BranchIdenticalStatusSymbol + } + elseif (($status.BehindBy -ge 1) -and ($status.AheadBy -ge 1)) { + # We are both behind and ahead of remote + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchBehindAndAheadStatusSymbol) + if ($s.BranchBehindAndAheadDisplay -eq "Full") { + $branchStatusTextSpan.Text = ("{0}{1} {2}{3}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy, $s.BranchAheadStatusSymbol.Text, $status.AheadBy) } - elseif ($status.UpstreamGone -eq $true) { - # Upstream branch is gone - $branchStatusTextSpan = $s.BranchGoneStatusSymbol + elseif ($s.BranchBehindAndAheadDisplay -eq "Compact") { + $branchStatusTextSpan.Text = ("{0}{1}{2}" -f $status.BehindBy, $s.BranchBehindAndAheadStatusSymbol.Text, $status.AheadBy) } - elseif (($status.BehindBy -eq 0) -and ($status.AheadBy -eq 0)) { - # We are aligned with remote - $branchStatusTextSpan = $s.BranchIdenticalStatusSymbol + } + elseif ($status.BehindBy -ge 1) { + # We are behind remote + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchBehindStatusSymbol) + if (($s.BranchBehindAndAheadDisplay -eq "Full") -Or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { + $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy) } - elseif (($status.BehindBy -ge 1) -and ($status.AheadBy -ge 1)) { - $branchStatusTextSpan.ForegroundColor = $s.BranchBehindAndAheadStatusSymbol.ForegroundColor - $branchStatusTextSpan.BackgroundColor = $s.BranchBehindAndAheadStatusSymbol.BackgroundColor - - # We are both behind and ahead of remote - if ($s.BranchBehindAndAheadDisplay -eq "Full") { - $branchStatusTextSpan.Text = ("{0}{1} {2}{3}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy, $s.BranchAheadStatusSymbol.Text, $status.AheadBy) - } - elseif ($s.BranchBehindAndAheadDisplay -eq "Compact") { - $branchStatusTextSpan.Text = ("{0}{1}{2}" -f $status.BehindBy, $s.BranchBehindAndAheadStatusSymbol.Text, $status.AheadBy) - } - else { - $branchStatusTextSpan.Text = $s.BranchBehindAndAheadStatusSymbol.Text - } + } + elseif ($status.AheadBy -ge 1) { + # We are ahead of remote + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchAheadStatusSymbol) + if (($s.BranchBehindAndAheadDisplay -eq "Full") -or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { + $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchAheadStatusSymbol.Text, $status.AheadBy) } - elseif ($status.BehindBy -ge 1) { - $branchStatusTextSpan.ForegroundColor = $s.BranchBehindStatusSymbol.ForegroundColor - $branchStatusTextSpan.BackgroundColor = $s.BranchBehindStatusSymbol.BackgroundColor + } + else { + # This condition should not be possible but defaulting the variables to be safe + $branchStatusTextSpan.Text = "?" + } - # We are behind remote - if (($s.BranchBehindAndAheadDisplay -eq "Full") -Or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { - $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy) - } - else { - $branchStatusTextSpan.Text = $s.BranchBehindStatusSymbol.Text - } + $str = "" + if ($branchStatusTextSpan.Text) { + if ($StringBuilder) { + $StringBuilder | Write-Prompt $branchStatusTextSpan > $null } - elseif ($status.AheadBy -ge 1) { - $branchStatusTextSpan.ForegroundColor = $s.BranchAheadStatusSymbol.ForegroundColor - $branchStatusTextSpan.BackgroundColor = $s.BranchAheadStatusSymbol.BackgroundColor - - # We are ahead of remote - if (($s.BranchBehindAndAheadDisplay -eq "Full") -or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { - $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchAheadStatusSymbol.Text, $status.AheadBy) - } else { - $branchStatusTextSpan.Text = $s.BranchAheadStatusSymbol.Text - } - } - else { - # This condition should not be possible but defaulting the variables to be safe - $branchStatusTextSpan.Text = "?" + elseif ($PSCmdlet.ParameterSetName -ne "PoshGitTextSpan") { + $str = Write-Prompt $branchStatusTextSpan > $null } + } + + return $(if ($Builder) { $Builder } else { $str }) +} + +function Write-GitStatus($status) { + $s = $global:GitPromptSettings + $sb = [System.Text.StringBuilder]::new(150) + + if ($status -and $s) { + $sb | Write-Prompt $s.BeforeText > $null + + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) + + # This only populates $branchStatusTextSpan passed in. + Write-BranchStatus $status -BranchStatusTextSpan $branchStatusTextSpan + # Use the branch status colors (or CustomAnsi) to display the branch name $branchNameTextSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) $branchNameTextSpan.Text = Format-BranchName $status.Branch $sb | Write-Prompt $branchNameTextSpan > $null + # After we've written the branch name, now let's write the branch status if ($branchStatusTextSpan.Text) { $textSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) $textSpan.Text = " " + $branchStatusTextSpan.Text diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index 82be71d21..2403bf77a 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -28,6 +28,7 @@ FunctionsToExport = @( 'Get-GitDirectory', 'Update-AllBranches', 'Write-GitStatus', + 'Write-BranchStatus', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index 5d0b91926..996c2c376 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -135,6 +135,7 @@ $exportModuleMemberParams = @{ 'Get-GitStatus', 'Update-AllBranches', 'Write-GitStatus', + 'Write-BranchStatus', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', From 8fcfc21cbb41d81224f051b5f8bcf0ddafe30c11 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 29 Oct 2017 22:38:48 -0600 Subject: [PATCH 06/23] WIP refactor Write-GitStatus into individual Write-* methods. Not sure whether all these individual methods should be exposed but I'm inclined to expose them so folks can compose their Git status in their own order. --- src/GitPrompt.ps1 | 599 ++++++++++++++++++++++++++++++++++++---------- src/GitUtils.ps1 | 7 +- src/posh-git.psd1 | 6 + src/posh-git.psm1 | 6 + 4 files changed, 484 insertions(+), 134 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index b0c6d1ac4..273b5e65d 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -227,8 +227,8 @@ if ($Host.UI.RawUI.BackgroundColor -eq [ConsoleColor]::DarkMagenta) { # PowerShell 5.x only runs on Windows so use .NET types to determine isAdminProcess # Or if we are on v6 or higher, check the $IsWindows pre-defined variable. if (($PSVersionTable.PSVersion.Major -le 5) -or $IsWindows) { - $currentUser = [Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent()) - $isAdminProcess = $currentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + $currentUser = [System.Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent()) + $isAdminProcess = $currentUser.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) } else { # Must be Linux or OSX, so use the id util. Root has userid of 0. @@ -239,13 +239,15 @@ $adminHeader = if ($isAdminProcess) { 'Administrator: ' } else { '' } $WindowTitleSupported = $true # TODO: Hmm, this is a curious way to detemine window title supported +# Could do $host.Name -eq "Package Manager Host" but that is kinda specific +# Could attempt to change it and catch any exception and then set this to $false if (Get-Module NuGet) { $WindowTitleSupported = $false } function Write-Prompt { param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] $Object, [Parameter()] @@ -315,14 +317,184 @@ function Write-Prompt { return "" } -function Format-BranchName($branchName){ +<# +.SYNOPSIS + Writes the Git status for repo. Typically, you use Write-VcsStatus + function instead of this one. +.DESCRIPTION + Writes the Git status for repo. This includes the branch name, branch + status with respect to its remote (if exists), index status, working + dir status, working dir local status and stash count (optional). + Various settings from GitPromptSettngs are used to format and color + the Git status. + + On systems that support ANSI terminal sequences, this method will + return a string containing ANSI sequences to color various parts of + the Git status string. This string can be written to the host and + the ANSI sequences will be interpreted and converted to the specified + behaviors which is typically setting the foreground and/or background + color of text. +.EXAMPLE + PS C:\> Write-GitStatus (Get-GitStatus) + + Writes the Git status for the current repo. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + System.String + This command returns a System.String object. +#> +function Write-GitStatus { + param( + # The Git status, retrieved from Get-GitStatus, from which to write the stash count. + # If no other parameters are specified, the stash count is written to the host. + [Parameter(Position = 0)] + $Status + ) + + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + if ($global:PreviousWindowTitle) { + $Host.UI.RawUI.WindowTitle = $global:PreviousWindowTitle + } + + return "" + } + + $sb = [System.Text.StringBuilder]::new(150) + + $sb | Write-Prompt $s.BeforeText > $null + + # Use the branch status colors (or CustomAnsi) to display the branch name + $branchNameTextSpan = Get-BranchStatusColor $Status + $branchNameTextSpan.Text = Format-BranchName $Status.Branch + $sb | Write-Prompt $branchNameTextSpan > $null + + $sb | Write-BranchStatus $Status > $null + + if ($s.EnableFileStatus -and $Status.HasIndex) { + $sb | Write-Prompt $s.BeforeIndexText > $null + + $sb | Write-IndexStatus $Status > $null + + if ($Status.HasWorking) { + $sb | Write-Prompt $s.DelimText > $null + } + } + + if ($s.EnableFileStatus -and $Status.HasWorking) { + $sb | Write-WorkingDirectoryStatus $Status > $null + } + + $sb | Write-WorkingDirectoryLocalStatus $Status > $null + + if ($s.EnableStashStatus -and ($Status.StashCount -gt 0)) { + $sb | Write-StashCount $Status > $null + } + + $sb | Write-Prompt $s.AfterText > $null + + if ($WindowTitleSupported -and $s.EnableWindowTitle) { + if (!$global:PreviousWindowTitle) { + $global:PreviousWindowTitle = $Host.UI.RawUI.WindowTitle + } + + $repoName = Split-Path -Leaf (Split-Path $status.GitDir) + $prefix = if ($s.EnableWindowTitle -is [string]) { $s.EnableWindowTitle } else { '' } + $Host.UI.RawUI.WindowTitle = "$script:adminHeader$prefix$repoName [$($Status.Branch)]" + } + + return $sb.ToString() +} + +<# +.SYNOPSIS + Formats the branch name text according to $GitPromptSettings. +.DESCRIPTION + Formats the branch name text according the $GitPromptSettings: + BranchNameLimit and TruncatedBranchSuffix. +.EXAMPLE + PS C:\> $branchName = Format-BranchName (Get-GitStatus).Branch + + Gets the branch name formatted as specified by the user's $GitPromptSettings. +.INPUTS + System.String + This is the branch name as a string. +.OUTPUTS + System.String + This command returns a System.String object. +#> +function Format-BranchName { + param( + # The branch name to format according to the GitPromptSettings: + # BranchNameLimit and TruncatedBranchSuffix. + [Parameter(Position=0)] + [string] + $BranchName + ) + $s = $global:GitPromptSettings - if (($s.BranchNameLimit -gt 0) -and ($branchName.Length -gt $s.BranchNameLimit)) + if ($s -and $BranchName -and ($s.BranchNameLimit -gt 0) -and ($branchName.Length -gt $s.BranchNameLimit)) { - $branchName = "{0}{1}" -f $branchName.Substring(0,$s.BranchNameLimit), $s.TruncatedBranchSuffix + $branchName = "{0}{1}" -f $branchName.Substring(0, $s.BranchNameLimit), $s.TruncatedBranchSuffix } - return $branchName + $branchName +} + +<# +.SYNOPSIS + Gets the colors to use for the branch status. +.DESCRIPTION + Gets the colors to use for the branch status. This color is typically + used for the branch name as well. The default color is specified by + $GitPromptSettins.BranchColor. But depending on the Git status object + passed in, the colors could be changed to match that of one these + other $GitPromptSettings: BranchBehindAndAheadStatusSymbol, + BranchBehindStatusSymbol or BranchAheadStatusSymbol. +.EXAMPLE + PS C:\> $branchStatusColor = Get-BranchStatusColor (Get-GitStatus) + + Returns a PoshGitTextSpan with the foreground and background colors + for the branch status. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + PoshGitTextSpan + A PoshGitTextSpan with colors reflecting those to be used by + branch status symbols. +#> +function Get-BranchStatusColor { + param( + # The Git status, retrieved from Get-GitStatus. + [Parameter(Position = 0)] + $Status + ) + + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } + + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) + + if (($Status.BehindBy -ge 1) -and ($Status.AheadBy -ge 1)) { + # We are both behind and ahead of remote + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchBehindAndAheadStatusSymbol) + } + elseif ($Status.BehindBy -ge 1) { + # We are behind remote + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchBehindStatusSymbol) + } + elseif ($Status.AheadBy -ge 1) { + # We are ahead of remote + $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchAheadStatusSymbol) + } + + $branchStatusTextSpan.Text = '' + $branchStatusTextSpan } <# @@ -333,79 +505,67 @@ function Format-BranchName($branchName){ via the Get-GitStatus command. Branch status includes information about the upstream branch, how far behind and/or ahead the local branch is from the remote. .EXAMPLE -An example + PS C:\> Write-BranchStatus (Get-GitStatus) + Writes the status of the current branch to the host. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus .OUTPUTS System.String, System.Text.StringBuilder This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> function Write-BranchStatus { - [CmdletBinding(DefaultParameterSetName="Default")] param( # The Git status, retrieved from Get-GitStatus, from which to write the branch status. # If no other parameters are specified, that branch status is written to the host. - [Parameter(ParameterSetName = "Default")] - [Parameter(ParameterSetName = "PoshGitTextSpan")] - [Parameter(ParameterSetName = "StringBuilder")] - [Parameter(Mandatory, Position = 0)] - [ValidateNotNull()] - $status, - - # If specified the branch status is written into the provided BranchStatusTextSpan object. - [Parameter(ParameterSetName="PoshGitTextSpan")] - [PoshGitTextSpan] - $BranchStatusTextSpan, + [Parameter(Position = 0)] + $Status, # If specified the branch status is written into the provided StringBuilder object. - [Parameter(ParameterSetName = "StringBuilder", ValueFromPipeline = $true)] + [Parameter(ValueFromPipeline = $true)] [System.Text.StringBuilder] $StringBuilder ) $s = $global:GitPromptSettings - if (!$s) { - Write-Warning "$($MyInvocation.MyCommand.Name): `$global:GitPromptSettings variable not found. No BranchStatus generated." + if (!$Status -or !$s) { return $(if ($StringBuilder) { $StringBuilder } else { "" }) } - if (!$BranchStatusTextSpan) { - $BranchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) - } + $branchStatusTextSpan = Get-BranchStatusColor $Status - if (!$status.Upstream) { + if (!$Status.Upstream) { $branchStatusTextSpan.Text = $s.BranchUntrackedText } - elseif ($status.UpstreamGone -eq $true) { + elseif ($Status.UpstreamGone -eq $true) { # Upstream branch is gone - $branchStatusTextSpan = $s.BranchGoneStatusSymbol + $branchStatusTextSpan.Text = $s.BranchGoneStatusSymbol.Text } - elseif (($status.BehindBy -eq 0) -and ($status.AheadBy -eq 0)) { + elseif (($Status.BehindBy -eq 0) -and ($Status.AheadBy -eq 0)) { # We are aligned with remote - $branchStatusTextSpan = $s.BranchIdenticalStatusSymbol + $branchStatusTextSpan.Text = $s.BranchIdenticalStatusSymbol.Text } - elseif (($status.BehindBy -ge 1) -and ($status.AheadBy -ge 1)) { + elseif (($Status.BehindBy -ge 1) -and ($Status.AheadBy -ge 1)) { # We are both behind and ahead of remote - $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchBehindAndAheadStatusSymbol) if ($s.BranchBehindAndAheadDisplay -eq "Full") { - $branchStatusTextSpan.Text = ("{0}{1} {2}{3}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy, $s.BranchAheadStatusSymbol.Text, $status.AheadBy) + $branchStatusTextSpan.Text = ("{0}{1} {2}{3}" -f $s.BranchBehindStatusSymbol.Text, $Status.BehindBy, $s.BranchAheadStatusSymbol.Text, $status.AheadBy) } elseif ($s.BranchBehindAndAheadDisplay -eq "Compact") { - $branchStatusTextSpan.Text = ("{0}{1}{2}" -f $status.BehindBy, $s.BranchBehindAndAheadStatusSymbol.Text, $status.AheadBy) + $branchStatusTextSpan.Text = ("{0}{1}{2}" -f $Status.BehindBy, $s.BranchBehindAndAheadStatusSymbol.Text, $Status.AheadBy) } } - elseif ($status.BehindBy -ge 1) { + elseif ($Status.BehindBy -ge 1) { # We are behind remote - $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchBehindStatusSymbol) if (($s.BranchBehindAndAheadDisplay -eq "Full") -Or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { - $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchBehindStatusSymbol.Text, $status.BehindBy) + $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchBehindStatusSymbol.Text, $Status.BehindBy) } } - elseif ($status.AheadBy -ge 1) { + elseif ($Status.AheadBy -ge 1) { # We are ahead of remote - $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchAheadStatusSymbol) if (($s.BranchBehindAndAheadDisplay -eq "Full") -or ($s.BranchBehindAndAheadDisplay -eq "Compact")) { - $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchAheadStatusSymbol.Text, $status.AheadBy) + $branchStatusTextSpan.Text = ("{0}{1}" -f $s.BranchAheadStatusSymbol.Text, $Status.AheadBy) } } else { @@ -415,146 +575,323 @@ function Write-BranchStatus { $str = "" if ($branchStatusTextSpan.Text) { + $textSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) + $textSpan.Text = " " + $branchStatusTextSpan.Text + if ($StringBuilder) { - $StringBuilder | Write-Prompt $branchStatusTextSpan > $null + $StringBuilder | Write-Prompt $textSpan > $null } - elseif ($PSCmdlet.ParameterSetName -ne "PoshGitTextSpan") { - $str = Write-Prompt $branchStatusTextSpan > $null + else { + $str = Write-Prompt $textSpan } } - return $(if ($Builder) { $Builder } else { $str }) + return $(if ($StringBuilder) { $StringBuilder } else { $str }) } -function Write-GitStatus($status) { - $s = $global:GitPromptSettings - $sb = [System.Text.StringBuilder]::new(150) - - if ($status -and $s) { - $sb | Write-Prompt $s.BeforeText > $null +<# +.SYNOPSIS + Writes the index status text given the current Git status. +.DESCRIPTION + Writes the index status text given the current Git status. +.EXAMPLE + PS C:\> Write-IndexStatus (Get-GitStatus) - $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) + Writes the Git index status to the host. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + System.String, System.Text.StringBuilder + This command returns a System.String object unless the -StringBuilder parameter + is supplied. In this case, it returns a System.Text.StringBuilder. +#> +function Write-IndexStatus { + param( + # The Git status, retrieved from Get-GitStatus, from which to write the index status. + # If no other parameters are specified, that index status is written to the host. + [Parameter(Position = 0)] + $Status, - # This only populates $branchStatusTextSpan passed in. - Write-BranchStatus $status -BranchStatusTextSpan $branchStatusTextSpan + # If specified the index status is written into the provided StringBuilder object. + [Parameter(ValueFromPipeline = $true)] + [System.Text.StringBuilder] + $StringBuilder + ) - # Use the branch status colors (or CustomAnsi) to display the branch name - $branchNameTextSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) - $branchNameTextSpan.Text = Format-BranchName $status.Branch - $sb | Write-Prompt $branchNameTextSpan > $null + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } - # After we've written the branch name, now let's write the branch status - if ($branchStatusTextSpan.Text) { - $textSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) - $textSpan.Text = " " + $branchStatusTextSpan.Text - $sb | Write-Prompt $textSpan > $null - } + $str = "" - if ($s.EnableFileStatus -and $status.HasIndex) { - $sb | Write-Prompt $s.BeforeIndexText > $null + if ($Status.HasIndex) { + $indexStatusTextSpan = [PoshGitTextSpan]::new($s.IndexColor) - $statusTextSpan = [PoshGitTextSpan]::new($s.IndexColor) - if ($s.ShowStatusWhenZero -or $status.Index.Added) { - $statusTextSpan.Text = " $($s.FileAddedText)$($status.Index.Added.Count)" - $sb | Write-Prompt $statusTextSpan > $null + if ($s.ShowStatusWhenZero -or $Status.Index.Added) { + $indexStatusTextSpan.Text = " $($s.FileAddedText)$($Status.Index.Added.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $indexStatusTextSpan > $null } - - if ($s.ShowStatusWhenZero -or $status.Index.Modified) { - $statusTextSpan.Text = " $($s.FileModifiedText)$($status.Index.Modified.Count)" - $sb | Write-Prompt $statusTextSpan > $null + else { + $str += Write-Prompt $indexStatusTextSpan } + } - if ($s.ShowStatusWhenZero -or $status.Index.Deleted) { - $statusTextSpan.Text = " $($s.FileRemovedText)$($status.Index.Deleted.Count)" - $sb | Write-Prompt $statusTextSpan > $null + if ($s.ShowStatusWhenZero -or $status.Index.Modified) { + $indexStatusTextSpan.Text = " $($s.FileModifiedText)$($status.Index.Modified.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + } + else { + $str += Write-Prompt $indexStatusTextSpan } + } - if ($status.Index.Unmerged) { - $statusTextSpan.Text = " $($s.FileConflictedText)$($status.Index.Unmerged.Count)" - $sb | Write-Prompt $statusTextSpan > $null + if ($s.ShowStatusWhenZero -or $Status.Index.Deleted) { + $indexStatusTextSpan.Text = " $($s.FileRemovedText)$($Status.Index.Deleted.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + } + else { + $str += Write-Prompt $indexStatusTextSpan } + } - if($status.HasWorking) { - $sb | Write-Prompt $s.DelimText > $null + if ($Status.Index.Unmerged) { + $indexStatusTextSpan.Text = " $($s.FileConflictedText)$($Status.Index.Unmerged.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + } + else { + $str += Write-Prompt $indexStatusTextSpan } } + } - if ($s.EnableFileStatus -and $status.HasWorking) { - $workingTextSpan = [PoshGitTextSpan]::new($s.WorkingColor) + return $(if ($StringBuilder) { $StringBuilder } else { $str }) +} - if ($s.ShowStatusWhenZero -or $status.Working.Added) { - $workingTextSpan.Text = " $($s.FileAddedText)$($status.Working.Added.Count)" - $sb | Write-Prompt $workingTextSpan > $null - } +<# +.SYNOPSIS + Writes the working directory status text given the current Git status. +.DESCRIPTION + Writes the working directory status text given the current Git status. +.EXAMPLE + PS C:\> Write-WorkingDirectoryStatus (Get-GitStatus) + + Writes the Git working directory status to the host. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + System.String, System.Text.StringBuilder + This command returns a System.String object unless the -StringBuilder parameter + is supplied. In this case, it returns a System.Text.StringBuilder. +#> +function Write-WorkingDirectoryStatus { + param( + # The Git status, retrieved from Get-GitStatus, from which to write the working dir status. + # If no other parameters are specified, that working dir status is written to the host. + [Parameter(Position = 0)] + $Status, + + # If specified the working dir status is written into the provided StringBuilder object. + [Parameter(ValueFromPipeline = $true)] + [System.Text.StringBuilder] + $StringBuilder + ) + + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } + + $str = "" + + if ($Status.HasWorking) { + $workingTextSpan = [PoshGitTextSpan]::new($s.WorkingColor) - if ($s.ShowStatusWhenZero -or $status.Working.Modified) { - $workingTextSpan.Text = " $($s.FileModifiedText)$($status.Working.Modified.Count)" - $sb | Write-Prompt $workingTextSpan > $null + if ($s.ShowStatusWhenZero -or $Status.Working.Added) { + $workingTextSpan.Text = " $($s.FileAddedText)$($Status.Working.Added.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $workingTextSpan > $null + } + else { + $str += Write-Prompt $workingTextSpan } + } - if ($s.ShowStatusWhenZero -or $status.Working.Deleted) { - $workingTextSpan.Text = " $($s.FileRemovedText)$($status.Working.Deleted.Count)" - $sb | Write-Prompt $workingTextSpan > $null + if ($s.ShowStatusWhenZero -or $Status.Working.Modified) { + $workingTextSpan.Text = " $($s.FileModifiedText)$($Status.Working.Modified.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $workingTextSpan > $null + } + else { + $str += Write-Prompt $workingTextSpan } + } - if ($status.Working.Unmerged) { - $workingTextSpan.Text = " $($s.FileConflictedText)$($status.Working.Unmerged.Count)" - $sb | Write-Prompt $workingTextSpan > $null + if ($s.ShowStatusWhenZero -or $Status.Working.Deleted) { + $workingTextSpan.Text = " $($s.FileRemovedText)$($Status.Working.Deleted.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $workingTextSpan > $null + } + else { + $str += Write-Prompt $workingTextSpan } } - if ($status.HasWorking) { - # We have un-staged files in the working tree - $localStatusSymbol = $s.LocalWorkingStatusSymbol + if ($Status.Working.Unmerged) { + $workingTextSpan.Text = " $($s.FileConflictedText)$($Status.Working.Unmerged.Count)" + if ($StringBuilder) { + $StringBuilder | Write-Prompt $workingTextSpan > $null + } + else { + $str += Write-Prompt $workingTextSpan + } } - elseif ($status.HasIndex) { - # We have staged but uncommited files - $localStatusSymbol = $s.LocalStagedStatusSymbol + } + + return $(if ($StringBuilder) { $StringBuilder } else { $str }) +} + +<# +.SYNOPSIS + Writes the working directory local status text given the current Git status. +.DESCRIPTION + Writes the working directory local status text given the current Git status. +.EXAMPLE + PS C:\> Write-WorkingDirectoryLocalStatus (Get-GitStatus) + + Writes the Git working directory local status to the host. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + System.String, System.Text.StringBuilder + This command returns a System.String object unless the -StringBuilder parameter + is supplied. In this case, it returns a System.Text.StringBuilder. +#> +function Write-WorkingDirectoryLocalStatus { + param( + # The Git status, retrieved from Get-GitStatus, from which to write the working dir local status. + # If no other parameters are specified, that working dir local status is written to the host. + [Parameter(Position = 0)] + $Status, + + # If specified the working dir local status is written into the provided StringBuilder object. + [Parameter(ValueFromPipeline = $true)] + [System.Text.StringBuilder] + $StringBuilder + ) + + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } + + $str = "" + + # No uncommited changes + $localStatusSymbol = $s.LocalDefaultStatusSymbol + + if ($Status.HasWorking) { + # We have un-staged files in the working tree + $localStatusSymbol = $s.LocalWorkingStatusSymbol + } + elseif ($Status.HasIndex) { + # We have staged but uncommited files + $localStatusSymbol = $s.LocalStagedStatusSymbol + } + + if ($localStatusSymbol.Text) { + $textSpan = [PoshGitTextSpan]::new($localStatusSymbol) + $textSpan.Text = " " + $localStatusSymbol.Text + if ($StringBuilder) { + $StringBuilder | Write-Prompt $textSpan > $null } else { - # No uncommited changes - $localStatusSymbol = $s.LocalDefaultStatusSymbol + $str += Write-Prompt $textSpan } + } - if ($localStatusSymbol.Text) { - $textSpan = [PoshGitTextSpan]::new($localStatusSymbol) - $textSpan.Text = " " + $localStatusSymbol.Text - $sb | Write-Prompt $textSpan > $null - } + return $(if ($StringBuilder) { $StringBuilder } else { $str }) +} - if ($s.EnableStashStatus -and ($status.StashCount -gt 0)) { - $stashTextSpan = [PoshGitTextSpan]::new($s.StashColor) - $stashTextSpan.Text = "$($status.StashCount)" +<# +.SYNOPSIS + Writes the stash count given the current Git status. +.DESCRIPTION + Writes the stash count given the current Git status. +.EXAMPLE + PS C:\> Write-StashCount (Get-GitStatus) - $sb | Write-Prompt $s.BeforeStashText > $null - $sb | Write-Prompt $stashTextSpan > $null - $sb | Write-Prompt $s.AfterStashText > $null - } + Writes the Git stash count to the host. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + System.String, System.Text.StringBuilder + This command returns a System.String object unless the -StringBuilder parameter + is supplied. In this case, it returns a System.Text.StringBuilder. +#> +function Write-StashCount { + param( + # The Git status, retrieved from Get-GitStatus, from which to write the stash count. + # If no other parameters are specified, the stash count is written to the host. + [Parameter(Position = 0)] + $Status, - $sb | Write-Prompt $s.AfterText > $null + # If specified the working dir local status is written into the provided StringBuilder object. + [Parameter(ValueFromPipeline = $true)] + [System.Text.StringBuilder] + $StringBuilder + ) - if ($WindowTitleSupported -and $s.EnableWindowTitle) { - if (!$global:PreviousWindowTitle) { - $global:PreviousWindowTitle = $Host.UI.RawUI.WindowTitle - } + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } - $repoName = Split-Path -Leaf (Split-Path $status.GitDir) - $prefix = if ($s.EnableWindowTitle -is [string]) { $s.EnableWindowTitle } else { '' } - $Host.UI.RawUI.WindowTitle = "$script:adminHeader$prefix$repoName [$($status.Branch)]" - } + $str = "" - return $sb.ToString() - } - elseif ($global:PreviousWindowTitle) { - $Host.UI.RawUI.WindowTitle = $global:PreviousWindowTitle - return "" + if ($Status.StashCount -gt 0) { + $stashTextSpan = [PoshGitTextSpan]::new($s.StashColor) + $stashTextSpan.Text = "$($Status.StashCount)" + + if ($StringBuilder) { + $StringBuilder | Write-Prompt $s.BeforeStashText > $null + $StringBuilder | Write-Prompt $stashTextSpan > $null + $StringBuilder | Write-Prompt $s.AfterStashText > $null + } + else { + $str += Write-Prompt $s.BeforeStashText > $null + $str += Write-Prompt $stashTextSpan > $null + $str += Write-Prompt $s.AfterStashText > $null + } } + + return $(if ($StringBuilder) { $StringBuilder } else { $str }) } if (!(Test-Path Variable:Global:VcsPromptStatuses)) { $global:VcsPromptStatuses = @() } +<# +.SYNOPSIS + Writes all version control prompt statuses configured in $global:VscPromptStatuses. +.DESCRIPTION + Writes all version control prompt statuses configured in $global:VscPromptStatuses. + By default, this includes the PoshGit prompt status. +.EXAMPLE + PS C:\> Write-VcsStatus + + Writes all version control prompt statuses that have been configured + with the global variable $VscPromptStatuses +#> function Global:Write-VcsStatus { Set-ConsoleMode -ANSI $global:VcsPromptStatuses | ForEach-Object { & $_ } diff --git a/src/GitUtils.ps1 b/src/GitUtils.ps1 index 19af0282d..df8ad9754 100644 --- a/src/GitUtils.ps1 +++ b/src/GitUtils.ps1 @@ -197,8 +197,8 @@ function Get-GitStatus($gitDir = (Get-GitDirectory)) { $stashCount = 0 if($settings.EnableFileStatus -and !$(InDotGitOrBareRepoDir $gitDir) -and !$(InDisabledRepository)) { - if ($settings.EnableFileStatusFromCache -eq $null) { - $settings.EnableFileStatusFromCache = (Get-Module GitStatusCachePoshClient) -ne $null + if ($null -eq $settings.EnableFileStatusFromCache) { + $settings.EnableFileStatusFromCache = $null -ne (Get-Module GitStatusCachePoshClient) } if ($settings.EnableFileStatusFromCache) { @@ -370,7 +370,7 @@ function Get-TempEnv($key) { function Set-TempEnv($key, $value) { $path = Get-TempEnvPath($key) - if ($value -eq $null) { + if ($null -eq $value) { if (Test-Path $path) { Remove-Item $path } @@ -591,5 +591,6 @@ function Update-AllBranches($Upstream = 'master', [switch]$Quiet) { Write-Warning "Rebase failed for $branch" } } + git checkout -q $head } diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index 2403bf77a..6eda896d6 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -24,11 +24,17 @@ PowerShellVersion = '3.0' # Functions to export from this module FunctionsToExport = @( 'Add-PoshGitToProfile', + 'Format-BranchName', + 'Get-BranchStatusColor', 'Get-GitStatus', 'Get-GitDirectory', 'Update-AllBranches', 'Write-GitStatus', 'Write-BranchStatus', + 'Write-IndexStatus', + 'Write-StashCount', + 'Write-WorkingDirectoryStatus', + 'Write-WorkingDirectoryLocalStatus', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index 996c2c376..df2c85eb5 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -131,11 +131,17 @@ $ExecutionContext.SessionState.Module.OnRemove = { $exportModuleMemberParams = @{ Function = @( 'Add-PoshGitToProfile', + 'Format-BranchName', + 'Get-BranchStatusColor', 'Get-GitDirectory', 'Get-GitStatus', 'Update-AllBranches', 'Write-GitStatus', 'Write-BranchStatus', + 'Write-IndexStatus', + 'Write-StashCount', + 'Write-WorkingDirectoryStatus', + 'Write-WorkingDirectoryLocalStatus', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', From 7fb0d6d3d20daa64a79ba5b4ec8902050daa23c3 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 29 Oct 2017 22:50:18 -0600 Subject: [PATCH 07/23] Prefix new function nouns with "Git" --- src/GitPrompt.ps1 | 44 ++++++++++++++++++++++---------------------- src/posh-git.psd1 | 16 ++++++++-------- src/posh-git.psm1 | 14 +++++++------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 273b5e65d..41182326b 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -367,16 +367,16 @@ function Write-GitStatus { $sb | Write-Prompt $s.BeforeText > $null # Use the branch status colors (or CustomAnsi) to display the branch name - $branchNameTextSpan = Get-BranchStatusColor $Status - $branchNameTextSpan.Text = Format-BranchName $Status.Branch + $branchNameTextSpan = Get-GitBranchStatusColor $Status + $branchNameTextSpan.Text = Format-GitBranchName $Status.Branch $sb | Write-Prompt $branchNameTextSpan > $null - $sb | Write-BranchStatus $Status > $null + $sb | Write-GitBranchStatus $Status > $null if ($s.EnableFileStatus -and $Status.HasIndex) { $sb | Write-Prompt $s.BeforeIndexText > $null - $sb | Write-IndexStatus $Status > $null + $sb | Write-GitIndexStatus $Status > $null if ($Status.HasWorking) { $sb | Write-Prompt $s.DelimText > $null @@ -384,13 +384,13 @@ function Write-GitStatus { } if ($s.EnableFileStatus -and $Status.HasWorking) { - $sb | Write-WorkingDirectoryStatus $Status > $null + $sb | Write-GitWorkingDirectoryStatus $Status > $null } - $sb | Write-WorkingDirectoryLocalStatus $Status > $null + $sb | Write-GitWorkingDirectoryLocalStatus $Status > $null if ($s.EnableStashStatus -and ($Status.StashCount -gt 0)) { - $sb | Write-StashCount $Status > $null + $sb | Write-GitStashCount $Status > $null } $sb | Write-Prompt $s.AfterText > $null @@ -415,7 +415,7 @@ function Write-GitStatus { Formats the branch name text according the $GitPromptSettings: BranchNameLimit and TruncatedBranchSuffix. .EXAMPLE - PS C:\> $branchName = Format-BranchName (Get-GitStatus).Branch + PS C:\> $branchName = Format-GitBranchName (Get-GitStatus).Branch Gets the branch name formatted as specified by the user's $GitPromptSettings. .INPUTS @@ -425,7 +425,7 @@ function Write-GitStatus { System.String This command returns a System.String object. #> -function Format-BranchName { +function Format-GitBranchName { param( # The branch name to format according to the GitPromptSettings: # BranchNameLimit and TruncatedBranchSuffix. @@ -454,7 +454,7 @@ function Format-BranchName { other $GitPromptSettings: BranchBehindAndAheadStatusSymbol, BranchBehindStatusSymbol or BranchAheadStatusSymbol. .EXAMPLE - PS C:\> $branchStatusColor = Get-BranchStatusColor (Get-GitStatus) + PS C:\> $branchStatusColor = Get-GitBranchStatusColor (Get-GitStatus) Returns a PoshGitTextSpan with the foreground and background colors for the branch status. @@ -466,7 +466,7 @@ function Format-BranchName { A PoshGitTextSpan with colors reflecting those to be used by branch status symbols. #> -function Get-BranchStatusColor { +function Get-GitBranchStatusColor { param( # The Git status, retrieved from Get-GitStatus. [Parameter(Position = 0)] @@ -505,7 +505,7 @@ function Get-BranchStatusColor { via the Get-GitStatus command. Branch status includes information about the upstream branch, how far behind and/or ahead the local branch is from the remote. .EXAMPLE - PS C:\> Write-BranchStatus (Get-GitStatus) + PS C:\> Write-GitBranchStatus (Get-GitStatus) Writes the status of the current branch to the host. .INPUTS @@ -516,7 +516,7 @@ function Get-BranchStatusColor { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-BranchStatus { +function Write-GitBranchStatus { param( # The Git status, retrieved from Get-GitStatus, from which to write the branch status. # If no other parameters are specified, that branch status is written to the host. @@ -534,7 +534,7 @@ function Write-BranchStatus { return $(if ($StringBuilder) { $StringBuilder } else { "" }) } - $branchStatusTextSpan = Get-BranchStatusColor $Status + $branchStatusTextSpan = Get-GitBranchStatusColor $Status if (!$Status.Upstream) { $branchStatusTextSpan.Text = $s.BranchUntrackedText @@ -595,7 +595,7 @@ function Write-BranchStatus { .DESCRIPTION Writes the index status text given the current Git status. .EXAMPLE - PS C:\> Write-IndexStatus (Get-GitStatus) + PS C:\> Write-GitIndexStatus (Get-GitStatus) Writes the Git index status to the host. .INPUTS @@ -606,7 +606,7 @@ function Write-BranchStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-IndexStatus { +function Write-GitIndexStatus { param( # The Git status, retrieved from Get-GitStatus, from which to write the index status. # If no other parameters are specified, that index status is written to the host. @@ -679,7 +679,7 @@ function Write-IndexStatus { .DESCRIPTION Writes the working directory status text given the current Git status. .EXAMPLE - PS C:\> Write-WorkingDirectoryStatus (Get-GitStatus) + PS C:\> Write-GitWorkingDirectoryStatus (Get-GitStatus) Writes the Git working directory status to the host. .INPUTS @@ -690,7 +690,7 @@ function Write-IndexStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-WorkingDirectoryStatus { +function Write-GitWorkingDirectoryStatus { param( # The Git status, retrieved from Get-GitStatus, from which to write the working dir status. # If no other parameters are specified, that working dir status is written to the host. @@ -763,7 +763,7 @@ function Write-WorkingDirectoryStatus { .DESCRIPTION Writes the working directory local status text given the current Git status. .EXAMPLE - PS C:\> Write-WorkingDirectoryLocalStatus (Get-GitStatus) + PS C:\> Write-GitWorkingDirectoryLocalStatus (Get-GitStatus) Writes the Git working directory local status to the host. .INPUTS @@ -774,7 +774,7 @@ function Write-WorkingDirectoryStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-WorkingDirectoryLocalStatus { +function Write-GitWorkingDirectoryLocalStatus { param( # The Git status, retrieved from Get-GitStatus, from which to write the working dir local status. # If no other parameters are specified, that working dir local status is written to the host. @@ -826,7 +826,7 @@ function Write-WorkingDirectoryLocalStatus { .DESCRIPTION Writes the stash count given the current Git status. .EXAMPLE - PS C:\> Write-StashCount (Get-GitStatus) + PS C:\> Write-GitStashCount (Get-GitStatus) Writes the Git stash count to the host. .INPUTS @@ -837,7 +837,7 @@ function Write-WorkingDirectoryLocalStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-StashCount { +function Write-GitStashCount { param( # The Git status, retrieved from Get-GitStatus, from which to write the stash count. # If no other parameters are specified, the stash count is written to the host. diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index 6eda896d6..f2b830bf7 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -24,18 +24,18 @@ PowerShellVersion = '3.0' # Functions to export from this module FunctionsToExport = @( 'Add-PoshGitToProfile', - 'Format-BranchName', - 'Get-BranchStatusColor', + 'Format-GitBranchName', + 'Get-GitBranchStatusColor', 'Get-GitStatus', 'Get-GitDirectory', 'Update-AllBranches', 'Write-GitStatus', - 'Write-BranchStatus', - 'Write-IndexStatus', - 'Write-StashCount', - 'Write-WorkingDirectoryStatus', - 'Write-WorkingDirectoryLocalStatus', - 'Write-Prompt', + 'Write-GitBranchStatus', + 'Write-GitIndexStatus', + 'Write-GitStashCount', + 'Write-GitWorkingDirectoryStatus', + 'Write-GitWorkingDirectoryLocalStatus', +'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', 'Start-SshAgent', diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index df2c85eb5..952790739 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -131,17 +131,17 @@ $ExecutionContext.SessionState.Module.OnRemove = { $exportModuleMemberParams = @{ Function = @( 'Add-PoshGitToProfile', - 'Format-BranchName', - 'Get-BranchStatusColor', + 'Format-GitBranchName', + 'Get-GitBranchStatusColor', 'Get-GitDirectory', 'Get-GitStatus', 'Update-AllBranches', 'Write-GitStatus', - 'Write-BranchStatus', - 'Write-IndexStatus', - 'Write-StashCount', - 'Write-WorkingDirectoryStatus', - 'Write-WorkingDirectoryLocalStatus', + 'Write-GitBranchStatus', + 'Write-GitIndexStatus', + 'Write-GitStashCount', + 'Write-GitWorkingDirectoryStatus', + 'Write-GitWorkingDirectoryLocalStatus', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', From 8dee3e7a3e09099691dbd785e77070e01caf3c05 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 29 Oct 2017 23:07:45 -0600 Subject: [PATCH 08/23] Rename GitWorkingDirectory to GitWorkingDir --- src/GitPrompt.ps1 | 12 ++++++------ src/posh-git.psd1 | 6 +++--- src/posh-git.psm1 | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 41182326b..c965f7df5 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -384,10 +384,10 @@ function Write-GitStatus { } if ($s.EnableFileStatus -and $Status.HasWorking) { - $sb | Write-GitWorkingDirectoryStatus $Status > $null + $sb | Write-GitWorkingDirStatus $Status > $null } - $sb | Write-GitWorkingDirectoryLocalStatus $Status > $null + $sb | Write-GitWorkingDirLocalStatus $Status > $null if ($s.EnableStashStatus -and ($Status.StashCount -gt 0)) { $sb | Write-GitStashCount $Status > $null @@ -679,7 +679,7 @@ function Write-GitIndexStatus { .DESCRIPTION Writes the working directory status text given the current Git status. .EXAMPLE - PS C:\> Write-GitWorkingDirectoryStatus (Get-GitStatus) + PS C:\> Write-GitWorkingDirStatus (Get-GitStatus) Writes the Git working directory status to the host. .INPUTS @@ -690,7 +690,7 @@ function Write-GitIndexStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-GitWorkingDirectoryStatus { +function Write-GitWorkingDirStatus { param( # The Git status, retrieved from Get-GitStatus, from which to write the working dir status. # If no other parameters are specified, that working dir status is written to the host. @@ -763,7 +763,7 @@ function Write-GitWorkingDirectoryStatus { .DESCRIPTION Writes the working directory local status text given the current Git status. .EXAMPLE - PS C:\> Write-GitWorkingDirectoryLocalStatus (Get-GitStatus) + PS C:\> Write-GitWorkingDirLocalStatus (Get-GitStatus) Writes the Git working directory local status to the host. .INPUTS @@ -774,7 +774,7 @@ function Write-GitWorkingDirectoryStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-GitWorkingDirectoryLocalStatus { +function Write-GitWorkingDirLocalStatus { param( # The Git status, retrieved from Get-GitStatus, from which to write the working dir local status. # If no other parameters are specified, that working dir local status is written to the host. diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index f2b830bf7..01d342537 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -33,9 +33,9 @@ FunctionsToExport = @( 'Write-GitBranchStatus', 'Write-GitIndexStatus', 'Write-GitStashCount', - 'Write-GitWorkingDirectoryStatus', - 'Write-GitWorkingDirectoryLocalStatus', -'Write-Prompt', + 'Write-GitWorkingDirStatus', + 'Write-GitWorkingDirLocalStatus', + 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', 'Start-SshAgent', diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index 952790739..eea62d1af 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -140,8 +140,8 @@ $exportModuleMemberParams = @{ 'Write-GitBranchStatus', 'Write-GitIndexStatus', 'Write-GitStashCount', - 'Write-GitWorkingDirectoryStatus', - 'Write-GitWorkingDirectoryLocalStatus', + 'Write-GitWorkingDirStatus', + 'Write-GitWorkingDirLocalStatus', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', From 71a085a64b78f8e10b29e780cbf9b5abbb795523 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 27 Nov 2017 21:25:47 -0700 Subject: [PATCH 09/23] Favor ConsoleColor over HtmlColor --- src/AnsiUtils.ps1 | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/AnsiUtils.ps1 b/src/AnsiUtils.ps1 index d5ee3a1dd..05fa5adcb 100644 --- a/src/AnsiUtils.ps1 +++ b/src/AnsiUtils.ps1 @@ -26,10 +26,10 @@ $ColorType = 'System.Drawing.Color' -as [Type] function EscapseAnsiString([string]$AnsiString) { if ($PSVersionTable.PSVersion.Major -ge 6) { - $res = $AnsiString -replace "$([char]0x1B)", '`e' + $res = $AnsiString -replace "$([char]27)", '`e' } else { - $res = $AnsiString -replace "$([char]0x1B)", '$([char]27)' + $res = $AnsiString -replace "$([char]27)", '$([char]27)' } $res @@ -49,13 +49,20 @@ function Get-VirtualTerminalSequence ($color, [int]$offset = 0) { return "${AnsiEscape}$(38 + $offset);5;${color}m" } + if ($color -is [int]) { + $r = ($color -shr 16) -band 0xff + $g = ($color -shr 8) -band 0xff + $b = $color -band 0xff + return "${AnsiEscape}$(38 + $offset);2;${r};${g};${b}m" + } + if ($color -is [String]) { try { - if ($ColorTranslatorType) { - $color = $ColorTranslatorType::FromHtml($color) + if ($color -as [ConsoleColor]) { + $color = [System.ConsoleColor]$color } - else { - $color = [ConsoleColor]$color + elseif ($ColorTranslatorType) { + $color = $ColorTranslatorType::FromHtml($color) } } catch { From fa2b05bb99f15abc5f7d8dfd09d291e0f5a5709a Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 27 Nov 2017 21:38:49 -0700 Subject: [PATCH 10/23] Change var name from $res to $prompt --- src/posh-git.psm1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index eea62d1af..868764072 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -72,20 +72,20 @@ if ($ForcePoshGitPrompt -or !$currentPromptDef -or ($currentPromptDef -eq $defau $currentPath = "~" + $currentPath.SubString($Home.Length) } - $res = '' + $prompt = '' # Display default prompt prefix if not empty. $defaultPromptPrefix = [string]$GitPromptSettings.DefaultPromptPrefix if ($defaultPromptPrefix) { $expandedDefaultPromptPrefix = $ExecutionContext.SessionState.InvokeCommand.ExpandString($defaultPromptPrefix) - $res += Write-Prompt $expandedDefaultPromptPrefix + $prompt += Write-Prompt $expandedDefaultPromptPrefix } # Write the abbreviated current path - $res += Write-Prompt $currentPath + $prompt += Write-Prompt $currentPath # Write the Git status summary information - $res += Write-VcsStatus + $prompt += Write-VcsStatus # If stopped in the debugger, the prompt needs to indicate that in some fashion $hasInBreakpoint = [runspace]::DefaultRunspace.Debugger | Get-Member -Name InBreakpoint -MemberType property @@ -103,11 +103,12 @@ if ($ForcePoshGitPrompt -or !$currentPromptDef -or ($currentPromptDef -eq $defau if ($GitPromptSettings.DefaultPromptEnableTiming) { $sw.Stop() $elapsed = $sw.ElapsedMilliseconds - $res += Write-Prompt " ${elapsed}ms" + $prompt += Write-Prompt " ${elapsed}ms" } $global:LASTEXITCODE = $origLastExitCode - $res + $expandedPromptSuffix + $prompt += $expandedPromptSuffix + $prompt } # Set the posh-git prompt as the default prompt From facc87dadb1b0f3cd19541caba82da1da4d0ce38 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Thu, 28 Dec 2017 23:43:53 -0700 Subject: [PATCH 11/23] Convert from untyped settings to strongly typed settings This turns out to be important when you've changed the structure of the settings. For instance, setting $GitPromptSettings.BranchColor = [consolecolor]::red doesn't work as expected because BranchColor is supposed to be a [PoshGitCellColor] object. With the strongly typed settings, the above assignement will generate an error. The assignment should be $GitPromptSettings.BranchColor.ForegroundColor = [ConsoleColor]::. --- src/GitPrompt.ps1 | 121 ++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index c965f7df5..76a289fd6 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -154,66 +154,69 @@ class PoshGitTextSpan { } } -$global:GitPromptSettings = [pscustomobject]@{ - DefaultColor = [PoshGitCellColor]::new() - BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) - IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) - WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) - StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - - BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) - DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) - AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) - - LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) - LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) - - BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign - BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines - BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow - BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow - BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow - - BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) - AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) - - FileAddedText = '+' - FileModifiedText = '~' - FileRemovedText = '-' - FileConflictedText = '!' - BranchUntrackedText = '' - - BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]"Full" - - EnableStashStatus = $false - ShowStatusWhenZero = $true - AutoRefreshIndex = $true - - EnablePromptStatus = !$global:GitMissing - EnableFileStatus = $true - EnableFileStatusFromCache = $null - RepositoriesInWhichToDisableFileStatus = @() # Array of repository paths - DescribeStyle = '' - - EnableWindowTitle = 'posh~git ~ ' - - AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") - - DefaultPromptPrefix = '' - DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' - DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' - DefaultPromptEnableTiming = $false - DefaultPromptAbbreviateHomeDirectory = $false - - Debug = $false - - BranchNameLimit = 0 - TruncatedBranchSuffix = '...' +class GitPromptSettings { + [bool]$AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") + + [PoshGitCellColor]$DefaultColor = [PoshGitCellColor]::new() + [PoshGitCellColor]$BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) + + [PoshGitCellColor]$IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) + [PoshGitCellColor]$WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) + [PoshGitCellColor]$StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + [PoshGitCellColor]$ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + + [PoshGitTextSpan]$BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) + + [PoshGitTextSpan]$BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + [PoshGitTextSpan]$BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) + [PoshGitTextSpan]$AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) + + [PoshGitTextSpan]$LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + [PoshGitTextSpan]$LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) + [PoshGitTextSpan]$LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) + + [PoshGitTextSpan]$BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign + [PoshGitTextSpan]$BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines + [PoshGitTextSpan]$BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow + [PoshGitTextSpan]$BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow + [PoshGitTextSpan]$BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow + + [BranchBehindAndAheadDisplayOptions]$BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]::Full + + [string]$FileAddedText = '+' + [string]$FileModifiedText = '~' + [string]$FileRemovedText = '-' + [string]$FileConflictedText = '!' + [string]$BranchUntrackedText = '' + + [bool]$EnableStashStatus = $false + [bool]$ShowStatusWhenZero = $true + [bool]$AutoRefreshIndex = $true + + [bool]$EnablePromptStatus = !$global:GitMissing + [bool]$EnableFileStatus = $true + [Nullable[bool]]$EnableFileStatusFromCache = $null + [string[]]$RepositoriesInWhichToDisableFileStatus = @() + + [string]$DescribeStyle = '' + [psobject]$EnableWindowTitle = 'posh~git ~ ' + + [string]$DefaultPromptPrefix = '' + [string]$DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' + [string]$DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' + [bool]$DefaultPromptEnableTiming = $false + [bool]$DefaultPromptAbbreviateHomeDirectory = $false + + [int]$BranchNameLimit = 0 + [string]$TruncatedBranchSuffix = '...' + + [bool]$Debug = $false } +$global:GitPromptSettings = [GitPromptSettings]::new() + # Override some of the normal colors if the background color is set to the default DarkMagenta. $s = $global:GitPromptSettings if ($Host.UI.RawUI.BackgroundColor -eq [ConsoleColor]::DarkMagenta) { @@ -402,7 +405,7 @@ function Write-GitStatus { $repoName = Split-Path -Leaf (Split-Path $status.GitDir) $prefix = if ($s.EnableWindowTitle -is [string]) { $s.EnableWindowTitle } else { '' } - $Host.UI.RawUI.WindowTitle = "$script:adminHeader$prefix$repoName [$($Status.Branch)]" + $Host.UI.RawUI.WindowTitle = "${script:adminHeader}${prefix}${repoName} [$($Status.Branch)]" } return $sb.ToString() From 5120624915c0c41df163afb8a614b19d398e7eea Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 31 Dec 2017 18:04:32 -0700 Subject: [PATCH 12/23] Add Write-GitBranchName Rename Write-GitWorkingDirLocalStatus to Write-GitWorkingDirStatusSummary Add -NoLeadingSpace parameter to individual Write-Git* functions to control output of leading space. --- src/GitPrompt.ps1 | 227 +++++++++++++++++++++++++++++++++++++++------- src/posh-git.psd1 | 3 +- src/posh-git.psm1 | 3 +- 3 files changed, 200 insertions(+), 33 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 76a289fd6..a8d08a980 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -368,12 +368,7 @@ function Write-GitStatus { $sb = [System.Text.StringBuilder]::new(150) $sb | Write-Prompt $s.BeforeText > $null - - # Use the branch status colors (or CustomAnsi) to display the branch name - $branchNameTextSpan = Get-GitBranchStatusColor $Status - $branchNameTextSpan.Text = Format-GitBranchName $Status.Branch - $sb | Write-Prompt $branchNameTextSpan > $null - + $sb | Write-GitBranchName $Status -NoLeadingSpace > $null $sb | Write-GitBranchStatus $Status > $null if ($s.EnableFileStatus -and $Status.HasIndex) { @@ -390,7 +385,7 @@ function Write-GitStatus { $sb | Write-GitWorkingDirStatus $Status > $null } - $sb | Write-GitWorkingDirLocalStatus $Status > $null + $sb | Write-GitWorkingDirStatusSummary $Status > $null if ($s.EnableStashStatus -and ($Status.StashCount -gt 0)) { $sb | Write-GitStashCount $Status > $null @@ -438,12 +433,17 @@ function Format-GitBranchName { ) $s = $global:GitPromptSettings - if ($s -and $BranchName -and ($s.BranchNameLimit -gt 0) -and ($branchName.Length -gt $s.BranchNameLimit)) + if (!$s -or !$BranchName) { + return "$BranchName" + } + + $res = $BranchName + if (($s.BranchNameLimit -gt 0) -and ($BranchName.Length -gt $s.BranchNameLimit)) { - $branchName = "{0}{1}" -f $branchName.Substring(0, $s.BranchNameLimit), $s.TruncatedBranchSuffix + $res = "{0}{1}" -f $BranchName.Substring(0, $s.BranchNameLimit), $s.TruncatedBranchSuffix } - $branchName + $res } <# @@ -477,8 +477,8 @@ function Get-GitBranchStatusColor { ) $s = $global:GitPromptSettings - if (!$Status -or !$s) { - return $(if ($StringBuilder) { $StringBuilder } else { "" }) + if (!$s) { + return [PoshGitTextSpan]::new() } $branchStatusTextSpan = [PoshGitTextSpan]::new($s.BranchColor) @@ -500,6 +500,70 @@ function Get-GitBranchStatusColor { $branchStatusTextSpan } +<# +.SYNOPSIS + Writes the branch name given the current Git status. +.DESCRIPTION + Writes the branch name given the current Git status which can retrieved + via the Get-GitStatus command. Branch name can be affected by the + $GitPromptSettings: BranchColor, BranchNameLimit, TruncatedBranchSuffix + and Branch*StatusSymbol colors. +.EXAMPLE + PS C:\> Write-GitBranchName (Get-GitStatus) + + Outputs the name of the current branch. +.INPUTS + System.Management.Automation.PSCustomObject + This is PSCustomObject returned by Get-GitStatus +.OUTPUTS + System.String, System.Text.StringBuilder + This command returns a System.String object unless the -StringBuilder parameter + is supplied. In this case, it returns a System.Text.StringBuilder. +#> +function Write-GitBranchName { + param( + # The Git status, retrieved from Get-GitStatus, from which to write the branch status. + # If no other parameters are specified, that branch status is written to the host. + [Parameter(Position = 0)] + $Status, + + # If specified the branch name is written into the provided StringBuilder object. + [Parameter(ValueFromPipeline = $true)] + [System.Text.StringBuilder] + $StringBuilder, + + # If specified, suppresses the output of the leading space character. + [Parameter()] + [switch] + $NoLeadingSpace + ) + + $s = $global:GitPromptSettings + if (!$Status -or !$s) { + return $(if ($StringBuilder) { $StringBuilder } else { "" }) + } + + $str = "" + + # Use the branch status colors (or CustomAnsi) to display the branch name + $branchNameTextSpan = Get-GitBranchStatusColor $Status + $branchNameTextSpan.Text = Format-GitBranchName $Status.Branch + + $textSpan = [PoshGitTextSpan]::new($branchNameTextSpan) + if (!$NoLeadingSpace) { + $textSpan.Text = " " + $branchNameTextSpan.Text + } + + if ($StringBuilder) { + $StringBuilder | Write-Prompt $textSpan > $null + } + else { + $str = Write-Prompt $textSpan + } + + return $(if ($StringBuilder) { $StringBuilder } else { $str }) +} + <# .SYNOPSIS Writes the branch status text given the current Git status. @@ -529,7 +593,12 @@ function Write-GitBranchStatus { # If specified the branch status is written into the provided StringBuilder object. [Parameter(ValueFromPipeline = $true)] [System.Text.StringBuilder] - $StringBuilder + $StringBuilder, + + # If specified, suppresses the output of the leading space character. + [Parameter()] + [switch] + $NoLeadingSpace ) $s = $global:GitPromptSettings @@ -579,7 +648,9 @@ function Write-GitBranchStatus { $str = "" if ($branchStatusTextSpan.Text) { $textSpan = [PoshGitTextSpan]::new($branchStatusTextSpan) - $textSpan.Text = " " + $branchStatusTextSpan.Text + if (!$NoLeadingSpace) { + $textSpan.Text = " " + $branchStatusTextSpan.Text + } if ($StringBuilder) { $StringBuilder | Write-Prompt $textSpan > $null @@ -619,7 +690,12 @@ function Write-GitIndexStatus { # If specified the index status is written into the provided StringBuilder object. [Parameter(ValueFromPipeline = $true)] [System.Text.StringBuilder] - $StringBuilder + $StringBuilder, + + # If specified, suppresses the output of the leading space character. + [Parameter()] + [switch] + $NoLeadingSpace ) $s = $global:GitPromptSettings @@ -633,7 +709,16 @@ function Write-GitIndexStatus { $indexStatusTextSpan = [PoshGitTextSpan]::new($s.IndexColor) if ($s.ShowStatusWhenZero -or $Status.Index.Added) { - $indexStatusTextSpan.Text = " $($s.FileAddedText)$($Status.Index.Added.Count)" + if ($NoLeadingSpace) { + $indexStatusTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $indexStatusTextSpan.Text = " " + } + + $indexStatusTextSpan.Text += "$($s.FileAddedText)$($Status.Index.Added.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $indexStatusTextSpan > $null } @@ -643,7 +728,16 @@ function Write-GitIndexStatus { } if ($s.ShowStatusWhenZero -or $status.Index.Modified) { - $indexStatusTextSpan.Text = " $($s.FileModifiedText)$($status.Index.Modified.Count)" + if ($NoLeadingSpace) { + $indexStatusTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $indexStatusTextSpan.Text = " " + } + + $indexStatusTextSpan.Text += "$($s.FileModifiedText)$($status.Index.Modified.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $indexStatusTextSpan > $null } @@ -653,7 +747,16 @@ function Write-GitIndexStatus { } if ($s.ShowStatusWhenZero -or $Status.Index.Deleted) { - $indexStatusTextSpan.Text = " $($s.FileRemovedText)$($Status.Index.Deleted.Count)" + if ($NoLeadingSpace) { + $indexStatusTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $indexStatusTextSpan.Text = " " + } + + $indexStatusTextSpan.Text += "$($s.FileRemovedText)$($Status.Index.Deleted.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $indexStatusTextSpan > $null } @@ -663,7 +766,16 @@ function Write-GitIndexStatus { } if ($Status.Index.Unmerged) { - $indexStatusTextSpan.Text = " $($s.FileConflictedText)$($Status.Index.Unmerged.Count)" + if ($NoLeadingSpace) { + $indexStatusTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $indexStatusTextSpan.Text = " " + } + + $indexStatusTextSpan.Text += "$($s.FileConflictedText)$($Status.Index.Unmerged.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $indexStatusTextSpan > $null } @@ -703,7 +815,12 @@ function Write-GitWorkingDirStatus { # If specified the working dir status is written into the provided StringBuilder object. [Parameter(ValueFromPipeline = $true)] [System.Text.StringBuilder] - $StringBuilder + $StringBuilder, + + # If specified, suppresses the output of the leading space character. + [Parameter()] + [switch] + $NoLeadingSpace ) $s = $global:GitPromptSettings @@ -717,7 +834,16 @@ function Write-GitWorkingDirStatus { $workingTextSpan = [PoshGitTextSpan]::new($s.WorkingColor) if ($s.ShowStatusWhenZero -or $Status.Working.Added) { - $workingTextSpan.Text = " $($s.FileAddedText)$($Status.Working.Added.Count)" + if ($NoLeadingSpace) { + $workingTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $workingTextSpan.Text = " " + } + + $workingTextSpan.Text += "$($s.FileAddedText)$($Status.Working.Added.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $workingTextSpan > $null } @@ -727,7 +853,16 @@ function Write-GitWorkingDirStatus { } if ($s.ShowStatusWhenZero -or $Status.Working.Modified) { - $workingTextSpan.Text = " $($s.FileModifiedText)$($Status.Working.Modified.Count)" + if ($NoLeadingSpace) { + $workingTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $workingTextSpan.Text = " " + } + + $workingTextSpan.Text += "$($s.FileModifiedText)$($Status.Working.Modified.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $workingTextSpan > $null } @@ -737,7 +872,16 @@ function Write-GitWorkingDirStatus { } if ($s.ShowStatusWhenZero -or $Status.Working.Deleted) { - $workingTextSpan.Text = " $($s.FileRemovedText)$($Status.Working.Deleted.Count)" + if ($NoLeadingSpace) { + $workingTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $workingTextSpan.Text = " " + } + + $workingTextSpan.Text += "$($s.FileRemovedText)$($Status.Working.Deleted.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $workingTextSpan > $null } @@ -747,7 +891,16 @@ function Write-GitWorkingDirStatus { } if ($Status.Working.Unmerged) { - $workingTextSpan.Text = " $($s.FileConflictedText)$($Status.Working.Unmerged.Count)" + if ($NoLeadingSpace) { + $workingTextSpan.Text = "" + $NoLeadingSpace = $false + } + else { + $workingTextSpan.Text = " " + } + + $workingTextSpan.Text += "$($s.FileConflictedText)$($Status.Working.Unmerged.Count)" + if ($StringBuilder) { $StringBuilder | Write-Prompt $workingTextSpan > $null } @@ -762,13 +915,17 @@ function Write-GitWorkingDirStatus { <# .SYNOPSIS - Writes the working directory local status text given the current Git status. + Writes the working directory status summary text given the current Git status. .DESCRIPTION - Writes the working directory local status text given the current Git status. + Writes the working directory status summary text given the current Git status. + If there are any unstaged commits, the $GitPromptSettings.LocalWorkingStatusSymbol + will be output. If not, then if are any staged but uncommmited changes, the + $GitPromptSettings.LocalStagedStatusSymbol will be output. If not, then + $GitPromptSettings.LocalDefaultStatusSymbol will be output. .EXAMPLE - PS C:\> Write-GitWorkingDirLocalStatus (Get-GitStatus) + PS C:\> Write-GitWorkingDirStatusSummary (Get-GitStatus) - Writes the Git working directory local status to the host. + Outputs the Git working directory status summary text. .INPUTS System.Management.Automation.PSCustomObject This is PSCustomObject returned by Get-GitStatus @@ -777,7 +934,7 @@ function Write-GitWorkingDirStatus { This command returns a System.String object unless the -StringBuilder parameter is supplied. In this case, it returns a System.Text.StringBuilder. #> -function Write-GitWorkingDirLocalStatus { +function Write-GitWorkingDirStatusSummary { param( # The Git status, retrieved from Get-GitStatus, from which to write the working dir local status. # If no other parameters are specified, that working dir local status is written to the host. @@ -787,7 +944,12 @@ function Write-GitWorkingDirLocalStatus { # If specified the working dir local status is written into the provided StringBuilder object. [Parameter(ValueFromPipeline = $true)] [System.Text.StringBuilder] - $StringBuilder + $StringBuilder, + + # If specified, suppresses the output of the leading space character. + [Parameter()] + [switch] + $NoLeadingSpace ) $s = $global:GitPromptSettings @@ -811,7 +973,10 @@ function Write-GitWorkingDirLocalStatus { if ($localStatusSymbol.Text) { $textSpan = [PoshGitTextSpan]::new($localStatusSymbol) - $textSpan.Text = " " + $localStatusSymbol.Text + if (!$NoLeadingSpace) { + $textSpan.Text = " " + $localStatusSymbol.Text + } + if ($StringBuilder) { $StringBuilder | Write-Prompt $textSpan > $null } diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index 01d342537..715472fce 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -30,11 +30,12 @@ FunctionsToExport = @( 'Get-GitDirectory', 'Update-AllBranches', 'Write-GitStatus', + 'Write-GitBranchName', 'Write-GitBranchStatus', 'Write-GitIndexStatus', 'Write-GitStashCount', 'Write-GitWorkingDirStatus', - 'Write-GitWorkingDirLocalStatus', + 'Write-GitWorkingDirStatusSummary', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index 868764072..0495fb799 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -138,11 +138,12 @@ $exportModuleMemberParams = @{ 'Get-GitStatus', 'Update-AllBranches', 'Write-GitStatus', + 'Write-GitBranchName', 'Write-GitBranchStatus', 'Write-GitIndexStatus', 'Write-GitStashCount', 'Write-GitWorkingDirStatus', - 'Write-GitWorkingDirLocalStatus', + 'Write-GitWorkingDirStatusSummary', 'Write-Prompt', 'Write-VcsStatus', 'Get-SshAgent', From 88312b27b860fbf693416ef754704f1f17a6d606 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 31 Dec 2017 18:06:24 -0700 Subject: [PATCH 13/23] Fix a typo in help comment --- src/GitPrompt.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index a8d08a980..fbc10625c 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -511,7 +511,7 @@ function Get-GitBranchStatusColor { .EXAMPLE PS C:\> Write-GitBranchName (Get-GitStatus) - Outputs the name of the current branch. + Writes the name of the current branch. .INPUTS System.Management.Automation.PSCustomObject This is PSCustomObject returned by Get-GitStatus From b656d1ecbe636fc90745c67e88615476b87da49e Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 12:42:14 -0700 Subject: [PATCH 14/23] Prep branch for a possible publish as Beta1 ModuleVersion must use semver - major.minor.patch (no fourth part). Set Prerelease to `-beta1` per instructions on https://blogs.msdn.microsoft.com/powershell/2017/12/05/prerelease-versioning-added-to-powershellget-and-powershell-gallery/ Update copyright date to 2018. --- src/posh-git.psd1 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index 715472fce..d2278ade0 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -4,7 +4,7 @@ RootModule = 'posh-git.psm1' # Version number of this module. -ModuleVersion = '1.0.0.0' +ModuleVersion = '1.0.0' # ID used to uniquely identify this module GUID = '74c9fd30-734b-4c89-a8ae-7727ad21d1d5' @@ -13,13 +13,13 @@ GUID = '74c9fd30-734b-4c89-a8ae-7727ad21d1d5' Author = 'Keith Dahlby and contributors' # Copyright statement for this module -Copyright = '(c) 2010-2017 Keith Dahlby and contributors' +Copyright = '(c) 2010-2018 Keith Dahlby and contributors' # Description of the functionality provided by this module Description = 'Provides prompt with Git status summary information and tab completion for Git commands, parameters, remotes and branch names.' # Minimum version of the Windows PowerShell engine required by this module -PowerShellVersion = '3.0' +PowerShellVersion = '5.0' # Functions to export from this module FunctionsToExport = @( @@ -59,7 +59,6 @@ AliasesToExport = @() # Private data to pass to the module specified in RootModule/ModuleToProcess. # This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{ - PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. Tags = @('git', 'prompt', 'tab', 'tab-completion', 'tab-expansion', 'tabexpansion') @@ -73,10 +72,9 @@ PrivateData = @{ # ReleaseNotes of this module ReleaseNotes = 'https://github.com/dahlbyk/posh-git/blob/develop/CHANGELOG.md' - # TODO: REMOVE BEFOE RELEASE - PreReleaseVersion = 'pre00' + # TODO: REMOVE BEFORE FINAL RELEASE + Prerelease = '-beta1' } - } } From db734a6144db0abcdb2b466ff44237e0c7970d0f Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 14:04:03 -0700 Subject: [PATCH 15/23] Export $GitPromptScriptBlock variable Allow advanced users to invoke the $scriptblock from their own prompt functions. --- src/posh-git.psd1 | 2 +- src/posh-git.psm1 | 149 ++++++++++++++++++++++++---------------------- 2 files changed, 79 insertions(+), 72 deletions(-) diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index d2278ade0..a47566a3c 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -51,7 +51,7 @@ FunctionsToExport = @( CmdletsToExport = @() # Variables to export from this module -VariablesToExport = @() +VariablesToExport = @('GitPromptScriptBlock') # Aliases to export from this module AliasesToExport = @() diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index 0495fb799..b13c4006e 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -26,8 +26,78 @@ else { $defaultPromptDef = $initialSessionState.Commands['prompt'].Definition } -# If there is no prompt function or the prompt function is the default, replace the current prompt function definition -$poshGitPromptScriptBlock = $null +# The built-in posh-git prompt function in ScriptBlock form. +$GitPromptScriptBlock = { + $settings = $global:GitPromptSettings + if (!$settings) { + return "<`$GitPromptSettings not found> " + } + + if ($settings.DefaultPromptEnableTiming) { + $sw = [System.Diagnostics.Stopwatch]::StartNew() + } + + $origLastExitCode = $global:LASTEXITCODE + + # A UNC path has no drive so it's better to use the ProviderPath e.g. "\\server\share". + # However for any path with a drive defined, it's better to use the Path property. + # In this case, ProviderPath is "\LocalMachine\My"" whereas Path is "Cert:\LocalMachine\My". + # The latter is more desirable. + $pathInfo = $ExecutionContext.SessionState.Path.CurrentLocation + $currentPath = if ($pathInfo.Drive) { $pathInfo.Path } else { $pathInfo.ProviderPath } + + # File system paths are case-sensitive on Linux and case-insensitive on Windows and macOS + if (($PSVersionTable.PSVersion.Major -ge 6) -and $IsLinux) { + $stringComparison = [System.StringComparison]::Ordinal + } + else { + $stringComparison = [System.StringComparison]::OrdinalIgnoreCase + } + + # Abbreviate path by replacing beginning of path with ~ *iff* the path is in the user's home dir + $abbrevHomeDir = $settings.DefaultPromptAbbreviateHomeDirectory + if ($abbrevHomeDir -and $currentPath -and $currentPath.StartsWith($Home, $stringComparison)) { + $currentPath = "~" + $currentPath.SubString($Home.Length) + } + + $prompt = '' + + # Display default prompt prefix if not empty. + $defaultPromptPrefix = [string]$settings.DefaultPromptPrefix + if ($defaultPromptPrefix) { + $expandedDefaultPromptPrefix = $ExecutionContext.SessionState.InvokeCommand.ExpandString($defaultPromptPrefix) + $prompt += Write-Prompt $expandedDefaultPromptPrefix + } + + # Write the abbreviated current path + $prompt += Write-Prompt $currentPath + + # Write the Git status summary information + $prompt += Write-VcsStatus + + # If stopped in the debugger, the prompt needs to indicate that in some fashion + $hasInBreakpoint = [runspace]::DefaultRunspace.Debugger | Get-Member -Name InBreakpoint -MemberType property + $debugMode = (Test-Path Variable:/PSDebugContext) -or ($hasInBreakpoint -and [runspace]::DefaultRunspace.Debugger.InBreakpoint) + $promptSuffix = if ($debugMode) { $settings.DefaultPromptDebugSuffix } else { $settings.DefaultPromptSuffix } + + # If user specifies $null or empty string, set to ' ' to avoid "PS>" unexpectedly being displayed + if (!$promptSuffix) { + $promptSuffix = ' ' + } + + $expandedPromptSuffix = $ExecutionContext.SessionState.InvokeCommand.ExpandString($promptSuffix) + + # If prompt timing enabled, display elapsed milliseconds + if ($settings.DefaultPromptEnableTiming) { + $sw.Stop() + $elapsed = $sw.ElapsedMilliseconds + $prompt += Write-Prompt " ${elapsed}ms" + } + + $global:LASTEXITCODE = $origLastExitCode + $prompt += $expandedPromptSuffix + $prompt +} $currentPromptDef = if ($funcInfo = Get-Command prompt -ErrorAction SilentlyContinue) { $funcInfo.Definition } @@ -43,76 +113,10 @@ if (!$currentPromptDef) { function global:prompt { ' ' } } +# If there is no prompt function or the prompt function is the default, replace the current prompt function definition if ($ForcePoshGitPrompt -or !$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { - $poshGitPromptScriptBlock = { - if ($GitPromptSettings.DefaultPromptEnableTiming) { - $sw = [System.Diagnostics.Stopwatch]::StartNew() - } - $origLastExitCode = $global:LASTEXITCODE - - # A UNC path has no drive so it's better to use the ProviderPath e.g. "\\server\share". - # However for any path with a drive defined, it's better to use the Path property. - # In this case, ProviderPath is "\LocalMachine\My"" whereas Path is "Cert:\LocalMachine\My". - # The latter is more desirable. - $pathInfo = $ExecutionContext.SessionState.Path.CurrentLocation - $currentPath = if ($pathInfo.Drive) { $pathInfo.Path } else { $pathInfo.ProviderPath } - - # File system paths are case-sensitive on Linux and case-insensitive on Windows and macOS - if (($PSVersionTable.PSVersion.Major -ge 6) -and $IsLinux) { - $stringComparison = [System.StringComparison]::Ordinal - } - else { - $stringComparison = [System.StringComparison]::OrdinalIgnoreCase - } - - # Abbreviate path by replacing beginning of path with ~ *iff* the path is in the user's home dir - $abbrevHomeDir = $GitPromptSettings.DefaultPromptAbbreviateHomeDirectory - if ($abbrevHomeDir -and $currentPath -and $currentPath.StartsWith($Home, $stringComparison)) - { - $currentPath = "~" + $currentPath.SubString($Home.Length) - } - - $prompt = '' - - # Display default prompt prefix if not empty. - $defaultPromptPrefix = [string]$GitPromptSettings.DefaultPromptPrefix - if ($defaultPromptPrefix) { - $expandedDefaultPromptPrefix = $ExecutionContext.SessionState.InvokeCommand.ExpandString($defaultPromptPrefix) - $prompt += Write-Prompt $expandedDefaultPromptPrefix - } - - # Write the abbreviated current path - $prompt += Write-Prompt $currentPath - - # Write the Git status summary information - $prompt += Write-VcsStatus - - # If stopped in the debugger, the prompt needs to indicate that in some fashion - $hasInBreakpoint = [runspace]::DefaultRunspace.Debugger | Get-Member -Name InBreakpoint -MemberType property - $debugMode = (Test-Path Variable:/PSDebugContext) -or ($hasInBreakpoint -and [runspace]::DefaultRunspace.Debugger.InBreakpoint) - $promptSuffix = if ($debugMode) { $GitPromptSettings.DefaultPromptDebugSuffix } else { $GitPromptSettings.DefaultPromptSuffix } - - # If user specifies $null or empty string, set to ' ' to avoid "PS>" unexpectedly being displayed - if (!$promptSuffix) { - $promptSuffix = ' ' - } - - $expandedPromptSuffix = $ExecutionContext.SessionState.InvokeCommand.ExpandString($promptSuffix) - - # If prompt timing enabled, display elapsed milliseconds - if ($GitPromptSettings.DefaultPromptEnableTiming) { - $sw.Stop() - $elapsed = $sw.ElapsedMilliseconds - $prompt += Write-Prompt " ${elapsed}ms" - } - - $global:LASTEXITCODE = $origLastExitCode - $prompt += $expandedPromptSuffix - $prompt - } - # Set the posh-git prompt as the default prompt - Set-Item Function:\prompt -Value $poshGitPromptScriptBlock + Set-Item Function:\prompt -Value $GitPromptScriptBlock } # Install handler for removal/unload of the module @@ -121,7 +125,7 @@ $ExecutionContext.SessionState.Module.OnRemove = { # Check if the posh-git prompt function itself has been replaced. If so, do not restore the prompt function $promptDef = if ($funcInfo = Get-Command prompt -ErrorAction SilentlyContinue) { $funcInfo.Definition } - if ($promptDef -eq $poshGitPromptScriptBlock) { + if ($promptDef -eq $GitPromptScriptBlock) { Set-Item Function:\prompt -Value ([scriptblock]::Create($defaultPromptDef)) return } @@ -154,6 +158,9 @@ $exportModuleMemberParams = @{ 'TabExpansion', 'tgit' ) + Variable = @( + 'GitPromptScriptBlock' + ) } Export-ModuleMember @exportModuleMemberParams From 53cb658143413b868c45d180398b9384cae17aaf Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 17:34:25 -0700 Subject: [PATCH 16/23] Fix Write-VcsStatus issue with returning array of prompt strings PS Prompt wants a single string - not an array of strings. Address PR feedback on using PoshGitTextSpan in error handler. --- src/GitPrompt.ps1 | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 100fd71ca..80f44c786 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -1052,7 +1052,19 @@ if (!(Test-Path Variable:Global:VcsPromptStatuses)) { #> function Global:Write-VcsStatus { Set-ConsoleMode -ANSI - $global:VcsPromptStatuses | ForEach-Object { & $_ } + $OFS = "" + $sb = [System.Text.StringBuilder]::new(200) + + $global:VcsPromptStatuses | ForEach-Object { + $str = & $_ + if ($str) { + # $str is quoted in case we get back an array of strings, quoting it will flatten the array + # into a single string and $OFS="" will ensure no spaces between each array item. + $sb.Append("$str") > $null + } + } + + $sb.ToString() } # Add scriptblock that will execute for Write-VcsStatus @@ -1064,9 +1076,16 @@ $PoshGitVcsPrompt = { catch { $s = $global:GitPromptSettings if ($s) { - Write-Prompt $s.BeforeText - Write-Prompt "Error: $_" -BackgroundColor $s.ErrorColor.BackgroundColor -ForegroundColor $s.ErrorColor.ForegroundColor - Write-Prompt $s.AfterText + $errorTextSpan = [PoshGitTextSpan]::new($s.ErrorColor) + $errorTextSpan.Text = "PoshGitVcsPrompt error: $_" + + $sb = [System.Text.StringBuilder]::new() + + $sb | Write-Prompt $s.BeforeText > $null + $sb | Write-Prompt $errorTextSpan > $null + $sb | Write-Prompt $s.AfterText > $null + + $sb.ToString() } } } From a3a4ffe79dae259f9a615306ea3a0a02aba3f750 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 17:46:14 -0700 Subject: [PATCH 17/23] Address PR feedback on -Status param help --- src/GitPrompt.ps1 | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 80f44c786..14fda5ac1 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -340,8 +340,8 @@ function Write-Prompt { #> function Write-GitStatus { param( - # The Git status, retrieved from Get-GitStatus, from which to write the stash count. - # If no other parameters are specified, the stash count is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status ) @@ -461,7 +461,8 @@ function Format-GitBranchName { #> function Get-GitBranchStatusColor { param( - # The Git status, retrieved from Get-GitStatus. + # The Git status object that provides branch status information. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status ) @@ -512,8 +513,8 @@ function Get-GitBranchStatusColor { #> function Write-GitBranchName { param( - # The Git status, retrieved from Get-GitStatus, from which to write the branch status. - # If no other parameters are specified, that branch status is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status, @@ -575,8 +576,8 @@ function Write-GitBranchName { #> function Write-GitBranchStatus { param( - # The Git status, retrieved from Get-GitStatus, from which to write the branch status. - # If no other parameters are specified, that branch status is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status, @@ -672,8 +673,8 @@ function Write-GitBranchStatus { #> function Write-GitIndexStatus { param( - # The Git status, retrieved from Get-GitStatus, from which to write the index status. - # If no other parameters are specified, that index status is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status, @@ -797,8 +798,8 @@ function Write-GitIndexStatus { #> function Write-GitWorkingDirStatus { param( - # The Git status, retrieved from Get-GitStatus, from which to write the working dir status. - # If no other parameters are specified, that working dir status is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status, @@ -926,8 +927,8 @@ function Write-GitWorkingDirStatus { #> function Write-GitWorkingDirStatusSummary { param( - # The Git status, retrieved from Get-GitStatus, from which to write the working dir local status. - # If no other parameters are specified, that working dir local status is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status, @@ -997,8 +998,8 @@ function Write-GitWorkingDirStatusSummary { #> function Write-GitStashCount { param( - # The Git status, retrieved from Get-GitStatus, from which to write the stash count. - # If no other parameters are specified, the stash count is written to the host. + # The Git status object that provides the status information to be written. + # This object is retrieved via the Get-GitStatus command. [Parameter(Position = 0)] $Status, From 2af60e000e97c2f230fac28015f27cc83938b19d Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 20:00:07 -0700 Subject: [PATCH 18/23] Address PR feedback to move types to separate file --- src/GitPrompt.ps1 | 214 ------------------------------------------- src/PoshGitTypes.ps1 | 213 ++++++++++++++++++++++++++++++++++++++++++ src/posh-git.psm1 | 1 + 3 files changed, 214 insertions(+), 214 deletions(-) create mode 100644 src/PoshGitTypes.ps1 diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index 14fda5ac1..e69ef2e29 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -1,220 +1,6 @@ # Inspired by Mark Embling # http://www.markembling.info/view/my-ideal-powershell-prompt-with-git-integration -enum BranchBehindAndAheadDisplayOptions { Full; Compact; Minimal } - -class PoshGitCellColor { - [psobject]$BackgroundColor - [psobject]$ForegroundColor - - PoshGitCellColor() { - $this.ForegroundColor = $null - $this.BackgroundColor = $null - } - - PoshGitCellColor([psobject]$ForegroundColor) { - $this.ForegroundColor = $ForegroundColor - $this.BackgroundColor = $null - } - - PoshGitCellColor([psobject]$ForegroundColor, [psobject]$BackgroundColor) { - $this.ForegroundColor = $ForegroundColor - $this.BackgroundColor = $BackgroundColor - } - - hidden [string] ToString($color) { - $ansiTerm = "$([char]0x1b)[0m" - $colorSwatch = " " - - if (!$color) { - $str = "" - } - elseif (Test-VirtualTerminalSequece $color) { - $txt = EscapseAnsiString $color - $str = "${color}${colorSwatch}${ansiTerm} $txt" - } - else { - $str = "" - - if ($global:GitPromptSettings.AnsiConsole) { - $bg = Get-BackgroundVirtualTerminalSequence $color - $str += "${bg}${colorSwatch}${ansiTerm} " - } - - $str += $color.ToString() - } - - return $str - } - - [string] ToString() { - $str = "ForegroundColor: " - $str += $this.ToString($this.ForegroundColor) + ", " - $str += "BackgroundColor: " - $str += $this.ToString($this.BackgroundColor) - return $str - } -} - -class PoshGitTextSpan { - [string]$Text - [psobject]$BackgroundColor - [psobject]$ForegroundColor - [string]$CustomAnsi - - PoshGitTextSpan() { - $this.Text = "" - $this.ForegroundColor = $null - $this.BackgroundColor = $null - $this.CustomAnsi = $null - } - - PoshGitTextSpan([string]$Text) { - $this.Text = $Text - $this.ForegroundColor = $null - $this.BackgroundColor = $null - $this.CustomAnsi = $null - } - - PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor) { - $this.Text = $Text - $this.ForegroundColor = $ForegroundColor - $this.BackgroundColor = $null - $this.CustomAnsi = $null - } - - PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor, [psobject]$BackgroundColor) { - $this.Text = $Text - $this.ForegroundColor = $ForegroundColor - $this.BackgroundColor = $BackgroundColor - $this.CustomAnsi = $null - } - - PoshGitTextSpan([PoshGitTextSpan]$PoshGitTextSpan) { - $this.Text = $PoshGitTextSpan.Text - $this.ForegroundColor = $PoshGitTextSpan.ForegroundColor - $this.BackgroundColor = $PoshGitTextSpan.BackgroundColor - $this.CustomAnsi = $PoshGitTextSpan.CustomAnsi - } - - PoshGitTextSpan([PoshGitCellColor]$PoshGitCellColor) { - $this.Text = '' - $this.ForegroundColor = $PoshGitCellColor.ForegroundColor - $this.BackgroundColor = $PoshGitCellColor.BackgroundColor - $this.CustomAnsi = $null - } - - [string] ToString() { - if ($global:GitPromptSettings.AnsiConsole) { - if ($this.CustomAnsi) { - $e = [char]27 + "[" - $ansi = $this.CustomAnsi - $escAnsi = EscapseAnsiString $this.CustomAnsi - $txt = $this.RenderAnsi() - $str = "Text: '$txt',`t CustomAnsi: '${ansi}${escAnsi}${e}0m'" - } - else { - $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) - $txt = $this.RenderAnsi() - $str = "Text: '$txt',`t $($color.ToString())" - } - } - else { - $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) - $txt = $this.Text - $str = "Text: '$txt',`t $($color.ToString())" - } - - return $str - } - - [string] RenderAnsi() { - $e = [char]27 + "[" - $txt = $this.Text - - if ($this.CustomAnsi) { - $ansi = $this.CustomAnsi - $str = "${ansi}${txt}${e}0m" - } - else { - $bg = $this.BackgroundColor - if ($bg -and !(Test-VirtualTerminalSequece $bg)) { - $bg = Get-BackgroundVirtualTerminalSequence $bg - } - - $fg = $this.ForegroundColor - if ($fg -and !(Test-VirtualTerminalSequece $fg)) { - $fg = Get-ForegroundVirtualTerminalSequence $fg - } - - $str = "${fg}${bg}${txt}${e}0m" - } - - return $str - } -} - -class GitPromptSettings { - [bool]$AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") - - [PoshGitCellColor]$DefaultColor = [PoshGitCellColor]::new() - [PoshGitCellColor]$BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) - - [PoshGitCellColor]$IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) - [PoshGitCellColor]$WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) - [PoshGitCellColor]$StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - [PoshGitCellColor]$ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - - [PoshGitTextSpan]$BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) - [PoshGitTextSpan]$DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) - [PoshGitTextSpan]$AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) - - [PoshGitTextSpan]$BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - [PoshGitTextSpan]$BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) - [PoshGitTextSpan]$AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) - - [PoshGitTextSpan]$LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - [PoshGitTextSpan]$LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) - [PoshGitTextSpan]$LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) - - [PoshGitTextSpan]$BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign - [PoshGitTextSpan]$BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines - [PoshGitTextSpan]$BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow - [PoshGitTextSpan]$BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow - [PoshGitTextSpan]$BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow - - [BranchBehindAndAheadDisplayOptions]$BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]::Full - - [string]$FileAddedText = '+' - [string]$FileModifiedText = '~' - [string]$FileRemovedText = '-' - [string]$FileConflictedText = '!' - [string]$BranchUntrackedText = '' - - [bool]$EnableStashStatus = $false - [bool]$ShowStatusWhenZero = $true - [bool]$AutoRefreshIndex = $true - - [bool]$EnablePromptStatus = !$global:GitMissing - [bool]$EnableFileStatus = $true - [Nullable[bool]]$EnableFileStatusFromCache = $null - [string[]]$RepositoriesInWhichToDisableFileStatus = @() - - [string]$DescribeStyle = '' - [psobject]$EnableWindowTitle = 'posh~git ~ ' - - [string]$DefaultPromptPrefix = '' - [string]$DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' - [string]$DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' - [bool]$DefaultPromptEnableTiming = $false - [bool]$DefaultPromptAbbreviateHomeDirectory = $false - - [int]$BranchNameLimit = 0 - [string]$TruncatedBranchSuffix = '...' - - [bool]$Debug = $false -} - $global:GitPromptSettings = [GitPromptSettings]::new() # Override some of the normal colors if the background color is set to the default DarkMagenta. diff --git a/src/PoshGitTypes.ps1 b/src/PoshGitTypes.ps1 new file mode 100644 index 000000000..ce326b012 --- /dev/null +++ b/src/PoshGitTypes.ps1 @@ -0,0 +1,213 @@ +enum BranchBehindAndAheadDisplayOptions { Full; Compact; Minimal } + +class PoshGitCellColor { + [psobject]$BackgroundColor + [psobject]$ForegroundColor + + PoshGitCellColor() { + $this.ForegroundColor = $null + $this.BackgroundColor = $null + } + + PoshGitCellColor([psobject]$ForegroundColor) { + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $null + } + + PoshGitCellColor([psobject]$ForegroundColor, [psobject]$BackgroundColor) { + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $BackgroundColor + } + + hidden [string] ToString($color) { + $ansiTerm = "$([char]0x1b)[0m" + $colorSwatch = " " + + if (!$color) { + $str = "" + } + elseif (Test-VirtualTerminalSequece $color) { + $txt = EscapseAnsiString $color + $str = "${color}${colorSwatch}${ansiTerm} $txt" + } + else { + $str = "" + + if ($global:GitPromptSettings.AnsiConsole) { + $bg = Get-BackgroundVirtualTerminalSequence $color + $str += "${bg}${colorSwatch}${ansiTerm} " + } + + $str += $color.ToString() + } + + return $str + } + + [string] ToString() { + $str = "ForegroundColor: " + $str += $this.ToString($this.ForegroundColor) + ", " + $str += "BackgroundColor: " + $str += $this.ToString($this.BackgroundColor) + return $str + } +} + +class PoshGitTextSpan { + [string]$Text + [psobject]$BackgroundColor + [psobject]$ForegroundColor + [string]$CustomAnsi + + PoshGitTextSpan() { + $this.Text = "" + $this.ForegroundColor = $null + $this.BackgroundColor = $null + $this.CustomAnsi = $null + } + + PoshGitTextSpan([string]$Text) { + $this.Text = $Text + $this.ForegroundColor = $null + $this.BackgroundColor = $null + $this.CustomAnsi = $null + } + + PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor) { + $this.Text = $Text + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $null + $this.CustomAnsi = $null + } + + PoshGitTextSpan([string]$Text, [psobject]$ForegroundColor, [psobject]$BackgroundColor) { + $this.Text = $Text + $this.ForegroundColor = $ForegroundColor + $this.BackgroundColor = $BackgroundColor + $this.CustomAnsi = $null + } + + PoshGitTextSpan([PoshGitTextSpan]$PoshGitTextSpan) { + $this.Text = $PoshGitTextSpan.Text + $this.ForegroundColor = $PoshGitTextSpan.ForegroundColor + $this.BackgroundColor = $PoshGitTextSpan.BackgroundColor + $this.CustomAnsi = $PoshGitTextSpan.CustomAnsi + } + + PoshGitTextSpan([PoshGitCellColor]$PoshGitCellColor) { + $this.Text = '' + $this.ForegroundColor = $PoshGitCellColor.ForegroundColor + $this.BackgroundColor = $PoshGitCellColor.BackgroundColor + $this.CustomAnsi = $null + } + + [string] ToString() { + if ($global:GitPromptSettings.AnsiConsole) { + if ($this.CustomAnsi) { + $e = [char]27 + "[" + $ansi = $this.CustomAnsi + $escAnsi = EscapseAnsiString $this.CustomAnsi + $txt = $this.RenderAnsi() + $str = "Text: '$txt',`t CustomAnsi: '${ansi}${escAnsi}${e}0m'" + } + else { + $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) + $txt = $this.RenderAnsi() + $str = "Text: '$txt',`t $($color.ToString())" + } + } + else { + $color = [PoshGitCellColor]::new($this.ForegroundColor, $this.BackgroundColor) + $txt = $this.Text + $str = "Text: '$txt',`t $($color.ToString())" + } + + return $str + } + + [string] RenderAnsi() { + $e = [char]27 + "[" + $txt = $this.Text + + if ($this.CustomAnsi) { + $ansi = $this.CustomAnsi + $str = "${ansi}${txt}${e}0m" + } + else { + $bg = $this.BackgroundColor + if ($bg -and !(Test-VirtualTerminalSequece $bg)) { + $bg = Get-BackgroundVirtualTerminalSequence $bg + } + + $fg = $this.ForegroundColor + if ($fg -and !(Test-VirtualTerminalSequece $fg)) { + $fg = Get-ForegroundVirtualTerminalSequence $fg + } + + $str = "${fg}${bg}${txt}${e}0m" + } + + return $str + } +} + +class GitPromptSettings { + [bool]$AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") + + [PoshGitCellColor]$DefaultColor = [PoshGitCellColor]::new() + [PoshGitCellColor]$BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) + + [PoshGitCellColor]$IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) + [PoshGitCellColor]$WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) + [PoshGitCellColor]$StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + [PoshGitCellColor]$ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + + [PoshGitTextSpan]$BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) + + [PoshGitTextSpan]$BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + [PoshGitTextSpan]$BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) + [PoshGitTextSpan]$AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) + + [PoshGitTextSpan]$LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + [PoshGitTextSpan]$LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) + [PoshGitTextSpan]$LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) + + [PoshGitTextSpan]$BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign + [PoshGitTextSpan]$BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines + [PoshGitTextSpan]$BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow + [PoshGitTextSpan]$BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow + [PoshGitTextSpan]$BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow + + [BranchBehindAndAheadDisplayOptions]$BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]::Full + + [string]$FileAddedText = '+' + [string]$FileModifiedText = '~' + [string]$FileRemovedText = '-' + [string]$FileConflictedText = '!' + [string]$BranchUntrackedText = '' + + [bool]$EnableStashStatus = $false + [bool]$ShowStatusWhenZero = $true + [bool]$AutoRefreshIndex = $true + + [bool]$EnablePromptStatus = !$global:GitMissing + [bool]$EnableFileStatus = $true + [Nullable[bool]]$EnableFileStatusFromCache = $null + [string[]]$RepositoriesInWhichToDisableFileStatus = @() + + [string]$DescribeStyle = '' + [psobject]$EnableWindowTitle = 'posh~git ~ ' + + [string]$DefaultPromptPrefix = '' + [string]$DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' + [string]$DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' + [bool]$DefaultPromptEnableTiming = $false + [bool]$DefaultPromptAbbreviateHomeDirectory = $false + + [int]$BranchNameLimit = 0 + [string]$TruncatedBranchSuffix = '...' + + [bool]$Debug = $false +} diff --git a/src/posh-git.psm1 b/src/posh-git.psm1 index b13c4006e..43db716e7 100644 --- a/src/posh-git.psm1 +++ b/src/posh-git.psm1 @@ -5,6 +5,7 @@ param([switch]$NoVersionWarn, [switch]$ForcePoshGitPrompt) . $PSScriptRoot\ConsoleMode.ps1 . $PSScriptRoot\Utils.ps1 . $PSScriptRoot\AnsiUtils.ps1 +. $PSScriptRoot\PoshGitTypes.ps1 . $PSScriptRoot\GitUtils.ps1 . $PSScriptRoot\GitPrompt.ps1 . $PSScriptRoot\GitParamTabExpansion.ps1 From 62357347b120e35b7bb8a056e96fa79fc8c75f6a Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 21:57:04 -0700 Subject: [PATCH 19/23] Adjust Prerelease field - set to `alpha` --- src/posh-git.psd1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/posh-git.psd1 b/src/posh-git.psd1 index a47566a3c..22898358f 100644 --- a/src/posh-git.psd1 +++ b/src/posh-git.psd1 @@ -72,8 +72,8 @@ PrivateData = @{ # ReleaseNotes of this module ReleaseNotes = 'https://github.com/dahlbyk/posh-git/blob/develop/CHANGELOG.md' - # TODO: REMOVE BEFORE FINAL RELEASE - Prerelease = '-beta1' + # OVERRIDE THIS FIELD FOR PUBLISHED RELEASES - LEAVE AT 'alpha' FOR CLONED/LOCAL REPO USAGE + Prerelease = 'alpha' } } From 9f9a649fd0a63c12bc76017e0f9ba9248aae945f Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 22:17:54 -0700 Subject: [PATCH 20/23] Address PR feedback - simplify Write-VcsStatus --- src/GitPrompt.ps1 | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index e69ef2e29..b4202d1d1 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -839,19 +839,9 @@ if (!(Test-Path Variable:Global:VcsPromptStatuses)) { #> function Global:Write-VcsStatus { Set-ConsoleMode -ANSI - $OFS = "" - $sb = [System.Text.StringBuilder]::new(200) - - $global:VcsPromptStatuses | ForEach-Object { - $str = & $_ - if ($str) { - # $str is quoted in case we get back an array of strings, quoting it will flatten the array - # into a single string and $OFS="" will ensure no spaces between each array item. - $sb.Append("$str") > $null - } - } - $sb.ToString() + $OFS = "" + "$($global:VcsPromptStatuses | ForEach-Object { & $_ })" } # Add scriptblock that will execute for Write-VcsStatus From 635c113247aa6374c58b677ab4ae6cca2357d5ad Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 1 Jan 2018 22:55:48 -0700 Subject: [PATCH 21/23] Address PR feedback - DarkCyan back to Cyan Also redo column alignment that got reset after paste into new file. --- src/PoshGitTypes.ps1 | 61 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/PoshGitTypes.ps1 b/src/PoshGitTypes.ps1 index ce326b012..98b1aa488 100644 --- a/src/PoshGitTypes.ps1 +++ b/src/PoshGitTypes.ps1 @@ -155,55 +155,56 @@ class GitPromptSettings { [bool]$AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") [PoshGitCellColor]$DefaultColor = [PoshGitCellColor]::new() - [PoshGitCellColor]$BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) + [PoshGitCellColor]$BranchColor = [PoshGitCellColor]::new([ConsoleColor]::Cyan) - [PoshGitCellColor]$IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) + [PoshGitCellColor]$IndexColor = [PoshGitCellColor]::new([ConsoleColor]::DarkGreen) [PoshGitCellColor]$WorkingColor = [PoshGitCellColor]::new([ConsoleColor]::DarkRed) - [PoshGitCellColor]$StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - [PoshGitCellColor]$ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + [PoshGitCellColor]$StashColor = [PoshGitCellColor]::new([ConsoleColor]::Red) + [PoshGitCellColor]$ErrorColor = [PoshGitCellColor]::new([ConsoleColor]::Red) - [PoshGitTextSpan]$BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) - [PoshGitTextSpan]$DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) - [PoshGitTextSpan]$AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$BeforeText = [PoshGitTextSpan]::new(' [', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$DelimText = [PoshGitTextSpan]::new(' |', [ConsoleColor]::Yellow) + [PoshGitTextSpan]$AfterText = [PoshGitTextSpan]::new(']', [ConsoleColor]::Yellow) - [PoshGitTextSpan]$BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) - [PoshGitTextSpan]$BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) - [PoshGitTextSpan]$AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) + [PoshGitTextSpan]$BeforeIndexText = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) + [PoshGitTextSpan]$BeforeStashText = [PoshGitTextSpan]::new(' (', [ConsoleColor]::Red) + [PoshGitTextSpan]$AfterStashText = [PoshGitTextSpan]::new(')', [ConsoleColor]::Red) [PoshGitTextSpan]$LocalDefaultStatusSymbol = [PoshGitTextSpan]::new('', [ConsoleColor]::DarkGreen) [PoshGitTextSpan]$LocalWorkingStatusSymbol = [PoshGitTextSpan]::new('!', [ConsoleColor]::DarkRed) - [PoshGitTextSpan]$LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::DarkCyan) + [PoshGitTextSpan]$LocalStagedStatusSymbol = [PoshGitTextSpan]::new('~', [ConsoleColor]::Cyan) - [PoshGitTextSpan]$BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign - [PoshGitTextSpan]$BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines - [PoshGitTextSpan]$BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow - [PoshGitTextSpan]$BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow + [PoshGitTextSpan]$BranchGoneStatusSymbol = [PoshGitTextSpan]::new([char]0x00D7, [ConsoleColor]::DarkCyan) # × Multiplication sign + [PoshGitTextSpan]$BranchIdenticalStatusSymbol = [PoshGitTextSpan]::new([char]0x2261, [ConsoleColor]::Cyan) # ≡ Three horizontal lines + [PoshGitTextSpan]$BranchAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2191, [ConsoleColor]::Green) # ↑ Up arrow + [PoshGitTextSpan]$BranchBehindStatusSymbol = [PoshGitTextSpan]::new([char]0x2193, [ConsoleColor]::Red) # ↓ Down arrow [PoshGitTextSpan]$BranchBehindAndAheadStatusSymbol = [PoshGitTextSpan]::new([char]0x2195, [ConsoleColor]::Yellow) # ↕ Up & Down arrow [BranchBehindAndAheadDisplayOptions]$BranchBehindAndAheadDisplay = [BranchBehindAndAheadDisplayOptions]::Full - [string]$FileAddedText = '+' - [string]$FileModifiedText = '~' - [string]$FileRemovedText = '-' - [string]$FileConflictedText = '!' + [string]$FileAddedText = '+' + [string]$FileModifiedText = '~' + [string]$FileRemovedText = '-' + [string]$FileConflictedText = '!' [string]$BranchUntrackedText = '' - [bool]$EnableStashStatus = $false - [bool]$ShowStatusWhenZero = $true - [bool]$AutoRefreshIndex = $true + [bool]$EnableStashStatus = $false + [bool]$ShowStatusWhenZero = $true + [bool]$AutoRefreshIndex = $true - [bool]$EnablePromptStatus = !$global:GitMissing - [bool]$EnableFileStatus = $true - [Nullable[bool]]$EnableFileStatusFromCache = $null + [bool]$EnablePromptStatus = !$global:GitMissing + [bool]$EnableFileStatus = $true + + [Nullable[bool]]$EnableFileStatusFromCache = $null [string[]]$RepositoriesInWhichToDisableFileStatus = @() - [string]$DescribeStyle = '' + [string]$DescribeStyle = '' [psobject]$EnableWindowTitle = 'posh~git ~ ' - [string]$DefaultPromptPrefix = '' - [string]$DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' - [string]$DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' - [bool]$DefaultPromptEnableTiming = $false + [string]$DefaultPromptPrefix = '' + [string]$DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) ' + [string]$DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) ' + [bool]$DefaultPromptEnableTiming = $false [bool]$DefaultPromptAbbreviateHomeDirectory = $false [int]$BranchNameLimit = 0 From 041c286c1ab9dd8e023603459e69c827a212635e Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Tue, 2 Jan 2018 23:35:28 -0700 Subject: [PATCH 22/23] Fix bug where color 'Black' wasn't matching ConsoleColor This is a weird one. I only found it by debugging the script. While `"Black" -as [ConsoleColor]` returns `System.ConsoleColor.Black`, that doesn't cause the `if` condition to be true. Ah, the issue is that the enum value for Black is 0. Doh! --- src/AnsiUtils.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AnsiUtils.ps1 b/src/AnsiUtils.ps1 index 05fa5adcb..5a0672edf 100644 --- a/src/AnsiUtils.ps1 +++ b/src/AnsiUtils.ps1 @@ -58,7 +58,7 @@ function Get-VirtualTerminalSequence ($color, [int]$offset = 0) { if ($color -is [String]) { try { - if ($color -as [ConsoleColor]) { + if ($null -ne ($color -as [System.ConsoleColor])) { $color = [System.ConsoleColor]$color } elseif ($ColorTranslatorType) { @@ -74,7 +74,7 @@ function Get-VirtualTerminalSequence ($color, [int]$offset = 0) { return "${AnsiEscape}$(38 + $offset);2;$($color.R);$($color.G);$($color.B)m" } - if (($color -is [ConsoleColor]) -and ($color -ge 0) -and ($color -le 15)) { + if (($color -is [System.ConsoleColor]) -and ($color -ge 0) -and ($color -le 15)) { return "${AnsiEscape}$($ConsoleColorToAnsi[$color] + $offset)m" } From 2831c0c9ff898d6561708f47d236311693a1a9c4 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Wed, 3 Jan 2018 00:30:15 -0700 Subject: [PATCH 23/23] Add -Color parameter to Write-Prompt This cleaned up a number of the Write-Git*Status functions a bit. Fixed bug in Write-GitStashCount where we were incorrectly redirecting the $str assignments to $null. --- src/GitPrompt.ps1 | 216 +++++++++++++++++++++++++--------------------- 1 file changed, 120 insertions(+), 96 deletions(-) diff --git a/src/GitPrompt.ps1 b/src/GitPrompt.ps1 index b4202d1d1..b522587c6 100644 --- a/src/GitPrompt.ps1 +++ b/src/GitPrompt.ps1 @@ -24,30 +24,79 @@ if (Get-Module NuGet) { $WindowTitleSupported = $false } +<# +.SYNOPSIS + Writes the object to the display or renders it as a string using ANSI/VT sequences. +.DESCRIPTION + Writes the specified object to the display unless $GitPromptSettings.AnsiConsole + is enabled. In this case, the Object is rendered, along with the specified + colors, as a string with the appropriate ANSI/VT sequences for colors embedded + in the string. If a StringBuilder is provided, the string is appended to the + StringBuilder. +.EXAMPLE + PS C:\> Write-Prompt "PS > " -ForegroundColor Cyan -BackgroundColor Black + On a system where $GitPromptSettings.AnsiConsole is set to $false, this + will write the above to the display using the Write-Host command. + If AnsiConsole is set to $true, this will return a string of the form: + "`e[96m`e[40mPS > `e[0m". +.EXAMPLE + PS C:\> $sb = [System.Text.StringBuilder]::new() + PS C:\> $sb | Write-Prompt "PS > " -ForegroundColor Cyan -BackgroundColor Black + On a system where $GitPromptSettings.AnsiConsole is set to $false, this + will write the above to the display using the Write-Host command. + If AnsiConsole is set to $true, this will append the following string to the + StringBuilder object piped into the command: + "`e[96m`e[40mPS > `e[0m". +#> function Write-Prompt { + [CmdletBinding(DefaultParameterSetName="Default")] param( - [Parameter(Mandatory)] + # Specifies objects to display in the console or render as a string if + # $GitPromptSettings.AnsiConsole is enabled. If the Object is of type + # [PoshGitTextSpan] the other color parameters are ignored since a + # [PoshGitTextSpan] provides the colors. + [Parameter(Mandatory, Position=0)] $Object, - [Parameter()] + # Specifies the foreground color. + [Parameter(ParameterSetName="Default")] $ForegroundColor = $null, - [Parameter()] + # Specifies the background color. + [Parameter(ParameterSetName="Default")] $BackgroundColor = $null, + # Specifies both the background and foreground colors via [PoshGitCellColor] object. + [Parameter(ParameterSetName="CellColor")] + [ValidateNotNull()] + [PoshGitCellColor] + $Color, + + # When specified and $GitPromptSettings.AnsiConsole is enabled, the Object parameter + # is written to the StringBuilder along with the appropriate ANSI/VT sequences for + # the specified foreground and background colors. [Parameter(ValueFromPipeline = $true)] [System.Text.StringBuilder] - $Builder + $StringBuilder ) + if ($PSCmdlet.ParameterSetName -eq "CellColor") { + $bgColor = $Color.BackgroundColor + $fgColor = $Color.ForegroundColor + } + else { + $bgColor = $BackgroundColor + $fgColor = $ForegroundColor + } + $s = $global:GitPromptSettings if ($s) { - if ($null -eq $ForegroundColor) { - $ForegroundColor = $s.DefaultColor.ForegroundColor + if ($null -eq $fgColor) { + $fgColor = $s.DefaultColor.ForegroundColor } - if ($null -eq $BackgroundColor) { - $BackgroundColor = $s.DefaultColor.BackgroundColor + if ($null -eq $bgColor) { + $bgColor = $s.DefaultColor.BackgroundColor } if ($s.AnsiConsole) { @@ -56,13 +105,13 @@ function Write-Prompt { } else { $e = [char]27 + "[" - $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor - $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor - $str = "${f}${b}${Object}${e}0m" + $fg = Get-ForegroundVirtualTerminalSequence $fgColor + $bg = Get-BackgroundVirtualTerminalSequence $bgColor + $str = "${fg}${bg}${Object}${e}0m" } - if ($Builder) { - return $Builder.Append($str) + if ($StringBuilder) { + return $StringBuilder.Append($str) } return $str @@ -70,8 +119,8 @@ function Write-Prompt { } if ($Object -is [PoshGitTextSpan]) { - $BackgroundColor = $Object.BackgroundColor - $ForegroundColor = $Object.ForegroundColor + $bgColor = $Object.BackgroundColor + $fgColor = $Object.ForegroundColor $Object = $Object.Text } @@ -80,17 +129,17 @@ function Write-Prompt { NoNewLine = $true; } - if ($BackgroundColor -and ($BackgroundColor -ge 0) -and ($BackgroundColor -le 15)) { - $writeHostParams.BackgroundColor = $BackgroundColor + if ($bgColor -and ($bgColor -ge 0) -and ($bgColor -le 15)) { + $writeHostParams.BackgroundColor = $bgColor } - if ($ForegroundColor -and ($ForegroundColor -ge 0) -and ($ForegroundColor -le 15)) { - $writeHostParams.ForegroundColor = $ForegroundColor + if ($fgColor -and ($fgColor -ge 0) -and ($fgColor -le 15)) { + $writeHostParams.ForegroundColor = $fgColor } Write-Host @writeHostParams - if ($Builder) { - return $Builder + if ($StringBuilder) { + return $StringBuilder } return "" @@ -325,17 +374,15 @@ function Write-GitBranchName { # Use the branch status colors (or CustomAnsi) to display the branch name $branchNameTextSpan = Get-GitBranchStatusColor $Status $branchNameTextSpan.Text = Format-GitBranchName $Status.Branch - - $textSpan = [PoshGitTextSpan]::new($branchNameTextSpan) if (!$NoLeadingSpace) { - $textSpan.Text = " " + $branchNameTextSpan.Text + $branchNameTextSpan.Text = " " + $branchNameTextSpan.Text } if ($StringBuilder) { - $StringBuilder | Write-Prompt $textSpan > $null + $StringBuilder | Write-Prompt $branchNameTextSpan > $null } else { - $str = Write-Prompt $textSpan + $str = Write-Prompt $branchNameTextSpan } return $(if ($StringBuilder) { $StringBuilder } else { $str }) @@ -483,81 +530,71 @@ function Write-GitIndexStatus { $str = "" if ($Status.HasIndex) { - $indexStatusTextSpan = [PoshGitTextSpan]::new($s.IndexColor) - if ($s.ShowStatusWhenZero -or $Status.Index.Added) { + $indexStatusText = " " if ($NoLeadingSpace) { - $indexStatusTextSpan.Text = "" + $indexStatusText = "" $NoLeadingSpace = $false } - else { - $indexStatusTextSpan.Text = " " - } - $indexStatusTextSpan.Text += "$($s.FileAddedText)$($Status.Index.Added.Count)" + $indexStatusText += "$($s.FileAddedText)$($Status.Index.Added.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + $StringBuilder | Write-Prompt $indexStatusText -Color $s.IndexColor > $null } else { - $str += Write-Prompt $indexStatusTextSpan + $str += Write-Prompt $indexStatusText -Color $s.IndexColor } } if ($s.ShowStatusWhenZero -or $status.Index.Modified) { + $indexStatusText = " " if ($NoLeadingSpace) { - $indexStatusTextSpan.Text = "" + $indexStatusText = "" $NoLeadingSpace = $false } - else { - $indexStatusTextSpan.Text = " " - } - $indexStatusTextSpan.Text += "$($s.FileModifiedText)$($status.Index.Modified.Count)" + $indexStatusText += "$($s.FileModifiedText)$($status.Index.Modified.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + $StringBuilder | Write-Prompt $indexStatusText -Color $s.IndexColor > $null } else { - $str += Write-Prompt $indexStatusTextSpan + $str += Write-Prompt $indexStatusText -Color $s.IndexColor } } if ($s.ShowStatusWhenZero -or $Status.Index.Deleted) { + $indexStatusText = " " if ($NoLeadingSpace) { - $indexStatusTextSpan.Text = "" + $indexStatusText = "" $NoLeadingSpace = $false } - else { - $indexStatusTextSpan.Text = " " - } - $indexStatusTextSpan.Text += "$($s.FileRemovedText)$($Status.Index.Deleted.Count)" + $indexStatusText += "$($s.FileRemovedText)$($Status.Index.Deleted.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + $StringBuilder | Write-Prompt $indexStatusText -Color $s.IndexColor > $null } else { - $str += Write-Prompt $indexStatusTextSpan + $str += Write-Prompt $indexStatusText -Color $s.IndexColor } } if ($Status.Index.Unmerged) { + $indexStatusText = " " if ($NoLeadingSpace) { - $indexStatusTextSpan.Text = "" + $indexStatusText = "" $NoLeadingSpace = $false } - else { - $indexStatusTextSpan.Text = " " - } - $indexStatusTextSpan.Text += "$($s.FileConflictedText)$($Status.Index.Unmerged.Count)" + $indexStatusText += "$($s.FileConflictedText)$($Status.Index.Unmerged.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $indexStatusTextSpan > $null + $StringBuilder | Write-Prompt $indexStatusText -Color $s.IndexColor > $null } else { - $str += Write-Prompt $indexStatusTextSpan + $str += Write-Prompt $indexStatusText -Color $s.IndexColor } } } @@ -608,81 +645,71 @@ function Write-GitWorkingDirStatus { $str = "" if ($Status.HasWorking) { - $workingTextSpan = [PoshGitTextSpan]::new($s.WorkingColor) - if ($s.ShowStatusWhenZero -or $Status.Working.Added) { + $workingStatusText = " " if ($NoLeadingSpace) { - $workingTextSpan.Text = "" + $workingStatusText = "" $NoLeadingSpace = $false } - else { - $workingTextSpan.Text = " " - } - $workingTextSpan.Text += "$($s.FileAddedText)$($Status.Working.Added.Count)" + $workingStatusText += "$($s.FileAddedText)$($Status.Working.Added.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $workingTextSpan > $null + $StringBuilder | Write-Prompt $workingStatusText -Color $s.WorkingColor > $null } else { - $str += Write-Prompt $workingTextSpan + $str += Write-Prompt $workingStatusText -Color $s.WorkingColor } } if ($s.ShowStatusWhenZero -or $Status.Working.Modified) { + $workingStatusText = " " if ($NoLeadingSpace) { - $workingTextSpan.Text = "" + $workingStatusText = "" $NoLeadingSpace = $false } - else { - $workingTextSpan.Text = " " - } - $workingTextSpan.Text += "$($s.FileModifiedText)$($Status.Working.Modified.Count)" + $workingStatusText += "$($s.FileModifiedText)$($Status.Working.Modified.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $workingTextSpan > $null + $StringBuilder | Write-Prompt $workingStatusText -Color $s.WorkingColor > $null } else { - $str += Write-Prompt $workingTextSpan + $str += Write-Prompt $workingStatusText -Color $s.WorkingColor } } if ($s.ShowStatusWhenZero -or $Status.Working.Deleted) { + $workingStatusText = " " if ($NoLeadingSpace) { - $workingTextSpan.Text = "" + $workingStatusText = "" $NoLeadingSpace = $false } - else { - $workingTextSpan.Text = " " - } - $workingTextSpan.Text += "$($s.FileRemovedText)$($Status.Working.Deleted.Count)" + $workingStatusText += "$($s.FileRemovedText)$($Status.Working.Deleted.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $workingTextSpan > $null + $StringBuilder | Write-Prompt $workingStatusText -Color $s.WorkingColor > $null } else { - $str += Write-Prompt $workingTextSpan + $str += Write-Prompt $workingStatusText -Color $s.WorkingColor } } if ($Status.Working.Unmerged) { + $workingStatusText = " " if ($NoLeadingSpace) { - $workingTextSpan.Text = "" + $workingStatusText = "" $NoLeadingSpace = $false } - else { - $workingTextSpan.Text = " " - } - $workingTextSpan.Text += "$($s.FileConflictedText)$($Status.Working.Unmerged.Count)" + $workingStatusText += "$($s.FileConflictedText)$($Status.Working.Unmerged.Count)" if ($StringBuilder) { - $StringBuilder | Write-Prompt $workingTextSpan > $null + $StringBuilder | Write-Prompt $workingStatusText -Color $s.WorkingColor > $null } else { - $str += Write-Prompt $workingTextSpan + $str += Write-Prompt $workingStatusText -Color $s.WorkingColor } } } @@ -803,18 +830,17 @@ function Write-GitStashCount { $str = "" if ($Status.StashCount -gt 0) { - $stashTextSpan = [PoshGitTextSpan]::new($s.StashColor) - $stashTextSpan.Text = "$($Status.StashCount)" + $stashText = "$($Status.StashCount)" if ($StringBuilder) { $StringBuilder | Write-Prompt $s.BeforeStashText > $null - $StringBuilder | Write-Prompt $stashTextSpan > $null + $StringBuilder | Write-Prompt $stashText -Color $s.StashColor > $null $StringBuilder | Write-Prompt $s.AfterStashText > $null } else { - $str += Write-Prompt $s.BeforeStashText > $null - $str += Write-Prompt $stashTextSpan > $null - $str += Write-Prompt $s.AfterStashText > $null + $str += Write-Prompt $s.BeforeStashText + $str += Write-Prompt $stashText -Color $s.StashColor + $str += Write-Prompt $s.AfterStashText } } @@ -853,13 +879,11 @@ $PoshGitVcsPrompt = { catch { $s = $global:GitPromptSettings if ($s) { - $errorTextSpan = [PoshGitTextSpan]::new($s.ErrorColor) - $errorTextSpan.Text = "PoshGitVcsPrompt error: $_" - + $errorText = "PoshGitVcsPrompt error: $_" $sb = [System.Text.StringBuilder]::new() $sb | Write-Prompt $s.BeforeText > $null - $sb | Write-Prompt $errorTextSpan > $null + $sb | Write-Prompt $errorText -Color $s.ErrorColor > $null $sb | Write-Prompt $s.AfterText > $null $sb.ToString()