diff --git a/GitPrompt.ps1 b/GitPrompt.ps1 index c3aaf913c..215f4524b 100644 --- a/GitPrompt.ps1 +++ b/GitPrompt.ps1 @@ -96,6 +96,9 @@ $global:GitPromptSettings = New-Object PSObject -Property @{ EnableWindowTitle = 'posh~git ~ ' + PromptSuffix = '> ' + PromptDebugSuffix = ' [DBG]>> ' + Debug = $false BranchNameLimit = 0 @@ -306,8 +309,4 @@ $PoshGitVcsPrompt = { Write-GitStatus $GitStatus } -# Install handler for removal/unload of the module $Global:VcsPromptStatuses += $PoshGitVcsPrompt -$ExecutionContext.SessionState.Module.OnRemove = { - $Global:VcsPromptStatuses = $Global:VcsPromptStatuses | Where-Object { $_ -ne $PoshGitVcsPrompt } -} diff --git a/posh-git.psd1 b/posh-git.psd1 index e888c5cda..d94163aa5 100644 --- a/posh-git.psd1 +++ b/posh-git.psd1 @@ -22,22 +22,24 @@ Description = 'A PowerShell environment for Git' PowerShellVersion = '2.0' # Functions to export from this module -FunctionsToExport = @('Invoke-NullCoalescing', - 'Write-GitStatus', - 'Write-Prompt', - 'Write-VcsStatus', - 'Get-GitStatus', - 'Enable-GitColors', - 'Get-GitDirectory', - 'TabExpansion', - 'Get-AliasPattern', - 'Get-SshAgent', - 'Start-SshAgent', - 'Stop-SshAgent', - 'Add-SshKey', - 'Get-SshPath', - 'Update-AllBranches', - 'tgit') +FunctionsToExport = @( + 'Invoke-NullCoalescing', + 'Write-GitStatus', + 'Write-Prompt', + 'Write-VcsStatus', + 'Get-GitStatus', + 'Enable-GitColors', + 'Get-GitDirectory', + 'TabExpansion', + 'Get-AliasPattern', + 'Get-SshAgent', + 'Start-SshAgent', + 'Stop-SshAgent', + 'Add-SshKey', + 'Get-SshPath', + 'Update-AllBranches', + 'tgit' +) # Cmdlets to export from this module CmdletsToExport = @() diff --git a/posh-git.psm1 b/posh-git.psm1 index 96efea065..bc310f9e9 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -1,4 +1,4 @@ -param([switch]$NoVersionWarn = $false) +param([switch]$NoVersionWarn) if (Get-Module posh-git) { return } @@ -11,15 +11,13 @@ if ($psv.Major -lt 3 -and !$NoVersionWarn) { "To suppress this warning, change your profile to include 'Import-Module posh-git -Args `$true'.") } -Push-Location $psScriptRoot -.\CheckVersion.ps1 > $null +& $PSScriptRoot\CheckVersion.ps1 > $null -. .\Utils.ps1 -. .\GitUtils.ps1 -. .\GitPrompt.ps1 -. .\GitTabExpansion.ps1 -. .\TortoiseGit.ps1 -Pop-Location +. $PSScriptRoot\Utils.ps1 +. $PSScriptRoot\GitUtils.ps1 +. $PSScriptRoot\GitPrompt.ps1 +. $PSScriptRoot\GitTabExpansion.ps1 +. $PSScriptRoot\TortoiseGit.ps1 if (!$Env:HOME) { $Env:HOME = "$Env:HOMEDRIVE$Env:HOMEPATH" } if (!$Env:HOME) { $Env:HOME = "$Env:USERPROFILE" } @@ -27,10 +25,84 @@ if (!$Env:HOME) { $Env:HOME = "$Env:USERPROFILE" } Get-TempEnv 'SSH_AGENT_PID' Get-TempEnv 'SSH_AUTH_SOCK' -Export-ModuleMember ` - -Alias @( - '??') ` - -Function @( +# Get the default prompt definition. +if ($psv.Major -eq 2) { + $defaultPromptDef = "`$(if (test-path variable:/PSDebugContext) { '[DBG]: ' } else { '' }) + 'PS ' + `$(Get-Location) + `$(if (`$nestedpromptlevel -ge 1) { '>>' }) + '> '" +} +else { + $defaultPromptDef = [Runspace]::DefaultRunspace.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 + +$currentPromptDef = if ($funcInfo = Get-Command prompt -ErrorAction SilentlyContinue) { $funcInfo.Definition } +if (!$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { + # Have to use [scriptblock]::Create() to get debugger detection to work in PS v2 + $poshGitPromptScriptBlock = [scriptblock]::Create(@' + $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 + if ($currentPath -and $currentPath.StartsWith($Home, $stringComparison)) + { + $currentPath = "~" + $currentPath.SubString($Home.Length) + } + + # Write the abbreviated current path + Write-Host $currentPath -NoNewline + + # Write the Git status summary information + Write-VcsStatus + + # If stopped in the debugger, the prompt needs to indicate that in some fashion + $debugMode = (Test-Path Variable:/PSDebugContext) -or [runspace]::DefaultRunspace.Debugger.InBreakpoint + $promptSuffix = if ($debugMode) { $GitPromptSettings.PromptDebugSuffix } else { $GitPromptSettings.PromptSuffix } + + # If user specifies $null or empty string, set to ' ' to avoid "PS>" unexpectedly being displayed + if (!$promptSuffix) { + $promptSuffix = ' ' + } + + $global:LASTEXITCODE = $origLastExitCode + $promptSuffix +'@) + + # Set the posh-git prompt as the default prompt + Set-Item Function:\prompt -Value $poshGitPromptScriptBlock +} + +# Install handler for removal/unload of the module +$ExecutionContext.SessionState.Module.OnRemove = { + $global:VcsPromptStatuses = $global:VcsPromptStatuses | Where-Object { $_ -ne $PoshGitVcsPrompt } + + # 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) { + Set-Item Function:\prompt -Value ([scriptblock]::Create($defaultPromptDef)) + return + } + + Write-Warning 'If your prompt function uses any posh-git commands, it will cause posh-git to be re-imported every time your prompt function is invoked.' +} + +$exportModuleMemberParams = @{ + Alias = @('??') # TODO: Remove in 1.0.0 + Function = @( 'Invoke-NullCoalescing', 'Write-GitStatus', 'Write-Prompt', @@ -46,6 +118,8 @@ Export-ModuleMember ` 'Add-SshKey', 'Get-SshPath', 'Update-AllBranches', - 'tgit') - + 'tgit' + ) +} +Export-ModuleMember @exportModuleMemberParams diff --git a/profile.example.ps1 b/profile.example.ps1 index d14f3769b..8247668ed 100644 --- a/profile.example.ps1 +++ b/profile.example.ps1 @@ -10,25 +10,6 @@ else { throw "Failed to import posh-git." } -# Set up a simple prompt that displays Git status summary info when inside of a Git repo. -function global:prompt { - $origLastExitCode = $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 - $curPath = if ($pathInfo.Drive) { $pathInfo.Path } else { $pathInfo.ProviderPath } - Write-Host $curPath -NoNewline - - # Write the Git status summary information to the host. - Write-VcsStatus - - $global:LASTEXITCODE = $origLastExitCode - "> " -} - # Settings for the prompt are in GitPrompt.ps1, so add any desired settings changes here. # Example: # $Global:GitPromptSettings.BranchBehindAndAheadDisplay = "Compact"