Skip to content

Commit d42d7a7

Browse files
authored
Merge pull request #447 from dahlbyk/SupportsVirtualTerminal
Use ANSI color codes if SupportsVirtualTerminal
2 parents 79fc86f + d3f4ca2 commit d42d7a7

File tree

5 files changed

+198
-24
lines changed

5 files changed

+198
-24
lines changed

src/AnsiUtils.ps1

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Color codes from https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
2+
$ConsoleColorToAnsi = @(
3+
30 # Black
4+
34 # DarkBlue
5+
32 # DarkGreen
6+
36 # DarkCyan
7+
31 # DarkRed
8+
35 # DarkMagenta
9+
33 # DarkYellow
10+
37 # Gray
11+
90 # DarkGray
12+
94 # Blue
13+
92 # Green
14+
96 # Cyan
15+
91 # Red
16+
95 # Magenta
17+
93 # Yellow
18+
97 # White
19+
)
20+
$AnsiDefaultColor = 39
21+
$AnsiEscape = [char]27 + "["
22+
23+
function Get-VirtualTerminalSequence ($color, [int]$offset = 0) {
24+
if (($color -is [ConsoleColor]) -and ($color -ge 0) -and ($color -le 15)) {
25+
return "${AnsiEscape}$($ConsoleColorToAnsi[$color] + $offset)m"
26+
}
27+
return "${AnsiEscape}$($AnsiDefaultColor + $offset)m"
28+
}
29+
30+
function Get-ForegroundVirtualTerminalSequence($Color) {
31+
return Get-VirtualTerminalSequence $Color
32+
}
33+
34+
function Get-BackgroundVirtualTerminalSequence($Color) {
35+
return Get-VirtualTerminalSequence $Color 10
36+
}

src/ConsoleMode.ps1

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Hack! https://gist.github.com/lzybkr/f2059cb2ee8d0c13c65ab933b75e998c
2+
3+
if ($IsWindows -eq $false) {
4+
function Set-ConsoleMode {
5+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
6+
param()
7+
}
8+
return
9+
}
10+
11+
Add-Type @"
12+
using System;
13+
using System.Runtime.InteropServices;
14+
15+
public class NativeConsoleMethods
16+
{
17+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
18+
public static extern IntPtr GetStdHandle(int handleId);
19+
20+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
21+
public static extern bool GetConsoleMode(IntPtr hConsoleOutput, out uint dwMode);
22+
23+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
24+
public static extern bool SetConsoleMode(IntPtr hConsoleOutput, uint dwMode);
25+
26+
public static uint GetConsoleMode(bool input = false)
27+
{
28+
var handle = GetStdHandle(input ? -10 : -11);
29+
uint mode;
30+
if (GetConsoleMode(handle, out mode))
31+
{
32+
return mode;
33+
}
34+
return 0xffffffff;
35+
}
36+
37+
public static uint SetConsoleMode(bool input, uint mode)
38+
{
39+
var handle = GetStdHandle(input ? -10 : -11);
40+
if (SetConsoleMode(handle, mode))
41+
{
42+
return GetConsoleMode(input);
43+
}
44+
return 0xffffffff;
45+
}
46+
}
47+
"@
48+
49+
[Flags()]
50+
enum ConsoleModeInputFlags
51+
{
52+
ENABLE_PROCESSED_INPUT = 0x0001
53+
ENABLE_LINE_INPUT = 0x0002
54+
ENABLE_ECHO_INPUT = 0x0004
55+
ENABLE_WINDOW_INPUT = 0x0008
56+
ENABLE_MOUSE_INPUT = 0x0010
57+
ENABLE_INSERT_MODE = 0x0020
58+
ENABLE_QUICK_EDIT_MODE = 0x0040
59+
ENABLE_EXTENDED_FLAGS = 0x0080
60+
ENABLE_AUTO_POSITION = 0x0100
61+
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0200
62+
}
63+
64+
[Flags()]
65+
enum ConsoleModeOutputFlags
66+
{
67+
ENABLE_PROCESSED_OUTPUT = 0x0001
68+
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
69+
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
70+
}
71+
72+
function Set-ConsoleMode
73+
{
74+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
75+
param(
76+
[Parameter(ParameterSetName = "ANSI")]
77+
[switch]
78+
$ANSI,
79+
80+
[Parameter(ParameterSetName = "Mode")]
81+
[uint32]
82+
$Mode,
83+
84+
[switch]
85+
$StandardInput
86+
)
87+
88+
if ($ANSI)
89+
{
90+
$outputMode = [NativeConsoleMethods]::GetConsoleMode($false)
91+
$null = [NativeConsoleMethods]::SetConsoleMode($false, $outputMode -bor [ConsoleModeOutputFlags]::ENABLE_VIRTUAL_TERMINAL_PROCESSING)
92+
93+
if ($StandardInput)
94+
{
95+
$inputMode = [NativeConsoleMethods]::GetConsoleMode($true)
96+
$null = [NativeConsoleMethods]::SetConsoleMode($true, $inputMode -bor [ConsoleModeInputFlags]::ENABLE_VIRTUAL_TERMINAL_PROCESSING)
97+
}
98+
}
99+
else
100+
{
101+
[NativeConsoleMethods]::SetConsoleMode($StandardInput, $Mode)
102+
}
103+
}

src/GitPrompt.ps1

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ $global:GitPromptSettings = [pscustomobject]@{
9797

9898
EnableWindowTitle = 'posh~git ~ '
9999

100+
AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON")
101+
100102
DefaultPromptPrefix = ''
101103
DefaultPromptSuffix = '$(''>'' * ($nestedPromptLevel + 1)) '
102104
DefaultPromptDebugSuffix = ' [DBG]$(''>'' * ($nestedPromptLevel + 1)) '
@@ -127,12 +129,35 @@ if (Get-Module NuGet) {
127129
$WindowTitleSupported = $false
128130
}
129131

130-
function Write-Prompt($Object, $ForegroundColor, $BackgroundColor = -1) {
132+
function Write-Prompt {
133+
param(
134+
[parameter(Mandatory = $true)]
135+
$Object,
136+
[parameter(Mandatory = $true)]
137+
$ForegroundColor,
138+
[parameter()]
139+
$BackgroundColor = $null,
140+
[parameter(ValueFromPipeline = $true)]
141+
[Text.StringBuilder]
142+
$Builder)
143+
if ($GitPromptSettings.AnsiConsole) {
144+
$e = [char]27 + "["
145+
$f = Get-ForegroundVirtualTerminalSequence $ForegroundColor
146+
$b = Get-BackgroundVirtualTerminalSequence $BackgroundColor
147+
if ($Builder) {
148+
return $Builder.Append($f).Append($b).Append($Object).Append($e).Append("0m")
149+
}
150+
return "${f}${b}${Object}${e}0m"
151+
}
131152
if ($BackgroundColor -lt 0) {
132153
Write-Host $Object -NoNewLine -ForegroundColor $ForegroundColor
133154
} else {
134155
Write-Host $Object -NoNewLine -ForegroundColor $ForegroundColor -BackgroundColor $BackgroundColor
135156
}
157+
if ($Builder) {
158+
return $Builder
159+
}
160+
return ""
136161
}
137162

138163
function Format-BranchName($branchName){
@@ -148,8 +173,9 @@ function Format-BranchName($branchName){
148173

149174
function Write-GitStatus($status) {
150175
$s = $global:GitPromptSettings
176+
$sb = New-Object System.Text.StringBuilder
151177
if ($status -and $s) {
152-
Write-Prompt $s.BeforeText -BackgroundColor $s.BeforeBackgroundColor -ForegroundColor $s.BeforeForegroundColor
178+
$sb | Write-Prompt $s.BeforeText -BackgroundColor $s.BeforeBackgroundColor -ForegroundColor $s.BeforeForegroundColor | Out-Null
153179

154180
$branchStatusText = $null
155181
$branchStatusBackgroundColor = $s.BranchBackgroundColor
@@ -201,47 +227,47 @@ function Write-GitStatus($status) {
201227
$branchStatusText = "?"
202228
}
203229

204-
Write-Prompt (Format-BranchName($status.Branch)) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor
230+
$sb | Write-Prompt (Format-BranchName($status.Branch)) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor | Out-Null
205231

206232
if ($branchStatusText) {
207-
Write-Prompt (" {0}" -f $branchStatusText) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor
233+
$sb | Write-Prompt (" {0}" -f $branchStatusText) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor | Out-Null
208234
}
209235

210236
if($s.EnableFileStatus -and $status.HasIndex) {
211-
Write-Prompt $s.BeforeIndexText -BackgroundColor $s.BeforeIndexBackgroundColor -ForegroundColor $s.BeforeIndexForegroundColor
237+
$sb | Write-Prompt $s.BeforeIndexText -BackgroundColor $s.BeforeIndexBackgroundColor -ForegroundColor $s.BeforeIndexForegroundColor | Out-Null
212238

213239
if($s.ShowStatusWhenZero -or $status.Index.Added) {
214-
Write-Prompt (" $($s.FileAddedText)$($status.Index.Added.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor
240+
$sb | Write-Prompt (" $($s.FileAddedText)$($status.Index.Added.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null
215241
}
216242
if($s.ShowStatusWhenZero -or $status.Index.Modified) {
217-
Write-Prompt (" $($s.FileModifiedText)$($status.Index.Modified.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor
243+
$sb | Write-Prompt (" $($s.FileModifiedText)$($status.Index.Modified.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null
218244
}
219245
if($s.ShowStatusWhenZero -or $status.Index.Deleted) {
220-
Write-Prompt (" $($s.FileRemovedText)$($status.Index.Deleted.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor
246+
$sb | Write-Prompt (" $($s.FileRemovedText)$($status.Index.Deleted.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null
221247
}
222248

223249
if ($status.Index.Unmerged) {
224-
Write-Prompt (" $($s.FileConflictedText)$($status.Index.Unmerged.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor
250+
$sb | Write-Prompt (" $($s.FileConflictedText)$($status.Index.Unmerged.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor | Out-Null
225251
}
226252

227253
if($status.HasWorking) {
228-
Write-Prompt $s.DelimText -BackgroundColor $s.DelimBackgroundColor -ForegroundColor $s.DelimForegroundColor
254+
$sb | Write-Prompt $s.DelimText -BackgroundColor $s.DelimBackgroundColor -ForegroundColor $s.DelimForegroundColor | Out-Null
229255
}
230256
}
231257

232258
if($s.EnableFileStatus -and $status.HasWorking) {
233259
if($s.ShowStatusWhenZero -or $status.Working.Added) {
234-
Write-Prompt (" $($s.FileAddedText)$($status.Working.Added.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor
260+
$sb | Write-Prompt (" $($s.FileAddedText)$($status.Working.Added.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null
235261
}
236262
if($s.ShowStatusWhenZero -or $status.Working.Modified) {
237-
Write-Prompt (" $($s.FileModifiedText)$($status.Working.Modified.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor
263+
$sb | Write-Prompt (" $($s.FileModifiedText)$($status.Working.Modified.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null
238264
}
239265
if($s.ShowStatusWhenZero -or $status.Working.Deleted) {
240-
Write-Prompt (" $($s.FileRemovedText)$($status.Working.Deleted.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor
266+
$sb | Write-Prompt (" $($s.FileRemovedText)$($status.Working.Deleted.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null
241267
}
242268

243269
if ($status.Working.Unmerged) {
244-
Write-Prompt (" $($s.FileConflictedText)$($status.Working.Unmerged.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor
270+
$sb | Write-Prompt (" $($s.FileConflictedText)$($status.Working.Unmerged.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor | Out-Null
245271
}
246272
}
247273

@@ -263,16 +289,16 @@ function Write-GitStatus($status) {
263289
}
264290

265291
if ($localStatusSymbol) {
266-
Write-Prompt (" {0}" -f $localStatusSymbol) -BackgroundColor $localStatusBackgroundColor -ForegroundColor $localStatusForegroundColor
292+
$sb | Write-Prompt (" {0}" -f $localStatusSymbol) -BackgroundColor $localStatusBackgroundColor -ForegroundColor $localStatusForegroundColor | Out-Null
267293
}
268294

269295
if ($s.EnableStashStatus -and ($status.StashCount -gt 0)) {
270-
Write-Prompt $s.BeforeStashText -BackgroundColor $s.BeforeStashBackgroundColor -ForegroundColor $s.BeforeStashForegroundColor
271-
Write-Prompt $status.StashCount -BackgroundColor $s.StashBackgroundColor -ForegroundColor $s.StashForegroundColor
272-
Write-Prompt $s.AfterStashText -BackgroundColor $s.AfterStashBackgroundColor -ForegroundColor $s.AfterStashForegroundColor
296+
$sb | Write-Prompt $s.BeforeStashText -BackgroundColor $s.BeforeStashBackgroundColor -ForegroundColor $s.BeforeStashForegroundColor | Out-Null
297+
$sb | Write-Prompt $status.StashCount -BackgroundColor $s.StashBackgroundColor -ForegroundColor $s.StashForegroundColor | Out-Null
298+
$sb | Write-Prompt $s.AfterStashText -BackgroundColor $s.AfterStashBackgroundColor -ForegroundColor $s.AfterStashForegroundColor | Out-Null
273299
}
274300

275-
Write-Prompt $s.AfterText -BackgroundColor $s.AfterBackgroundColor -ForegroundColor $s.AfterForegroundColor
301+
$sb | Write-Prompt $s.AfterText -BackgroundColor $s.AfterBackgroundColor -ForegroundColor $s.AfterForegroundColor | Out-Null
276302

277303
if ($WindowTitleSupported -and $s.EnableWindowTitle) {
278304
if( -not $Global:PreviousWindowTitle ) {
@@ -282,8 +308,11 @@ function Write-GitStatus($status) {
282308
$prefix = if ($s.EnableWindowTitle -is [string]) { $s.EnableWindowTitle } else { '' }
283309
$Host.UI.RawUI.WindowTitle = "$script:adminHeader$prefix$repoName [$($status.Branch)]"
284310
}
311+
312+
return $sb.ToString()
285313
} elseif ( $Global:PreviousWindowTitle ) {
286314
$Host.UI.RawUI.WindowTitle = $Global:PreviousWindowTitle
315+
return ""
287316
}
288317
}
289318

@@ -304,6 +333,7 @@ if ($Host.UI.RawUI.BackgroundColor -eq [ConsoleColor]::DarkMagenta) {
304333
}
305334

306335
function Global:Write-VcsStatus {
336+
Set-ConsoleMode -ANSI
307337
$Global:VcsPromptStatuses | ForEach-Object { & $_ }
308338
}
309339

src/posh-git.psm1

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ param([switch]$NoVersionWarn, [switch]$ForcePoshGitPrompt)
22

33
& $PSScriptRoot\CheckRequirements.ps1 > $null
44

5+
. $PSScriptRoot\ConsoleMode.ps1
56
. $PSScriptRoot\Utils.ps1
7+
. $PSScriptRoot\AnsiUtils.ps1
68
. $PSScriptRoot\GitUtils.ps1
79
. $PSScriptRoot\GitPrompt.ps1
810
. $PSScriptRoot\GitParamTabExpansion.ps1
@@ -70,18 +72,20 @@ if ($ForcePoshGitPrompt -or !$currentPromptDef -or ($currentPromptDef -eq $defau
7072
$currentPath = "~" + $currentPath.SubString($Home.Length)
7173
}
7274

75+
$res = ''
76+
7377
# Display default prompt prefix if not empty.
7478
$defaultPromptPrefix = [string]$GitPromptSettings.DefaultPromptPrefix
7579
if ($defaultPromptPrefix) {
7680
$expandedDefaultPromptPrefix = $ExecutionContext.SessionState.InvokeCommand.ExpandString($defaultPromptPrefix)
77-
Write-Host $expandedDefaultPromptPrefix -NoNewline
81+
$res += Write-Prompt $expandedDefaultPromptPrefix -ForegroundColor $GitPromptSettings.DefaultForegroundColor
7882
}
7983

8084
# Write the abbreviated current path
81-
Write-Host $currentPath -NoNewline
85+
$res += Write-Prompt $currentPath -ForegroundColor $GitPromptSettings.DefaultForegroundColor
8286

8387
# Write the Git status summary information
84-
Write-VcsStatus
88+
$res += Write-VcsStatus
8589

8690
# If stopped in the debugger, the prompt needs to indicate that in some fashion
8791
$hasInBreakpoint = [runspace]::DefaultRunspace.Debugger | Get-Member -Name InBreakpoint -MemberType property
@@ -99,11 +103,11 @@ if ($ForcePoshGitPrompt -or !$currentPromptDef -or ($currentPromptDef -eq $defau
99103
if ($GitPromptSettings.DefaultPromptEnableTiming) {
100104
$sw.Stop()
101105
$elapsed = $sw.ElapsedMilliseconds
102-
Write-Host " ${elapsed}ms" -NoNewline
106+
$res += Write-Prompt " ${elapsed}ms" -ForegroundColor $GitPromptSettings.DefaultForegroundColor
103107
}
104108

105109
$global:LASTEXITCODE = $origLastExitCode
106-
$expandedPromptSuffix
110+
$res + $expandedPromptSuffix
107111
}
108112

109113
# Set the posh-git prompt as the default prompt

test/DefaultPrompt.Tests.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Describe 'Default Prompt Tests' {
44
BeforeAll {
5+
$GitPromptSettings.AnsiConsole = $false
56
$prompt = Get-Item Function:\prompt
67
$OFS = ''
78
}

0 commit comments

Comments
 (0)