cmder/vendor/profile.ps1
Jackbennett 31c8c620c7 Custom prompt hooks protected from later overwriting
Add a pre and post function hook around the Cmder prompt.
Specify the cmder prompt as a function that could be replaced by a user.
Write a friendly message when the user profile template is created.
Create the user profile with cmder prompt hooks ready to use.

It was concerning to run any function with a specific name every prompt
with no guarantee it remains what it was initally created as.

Core functions have been explicitly called from their
namespace like Microsoft.PowerShell.Utility\Write-Host to try and prevent
clobbering.

User supplied functions are passed in as script blocks, created as the
session runs the profile script. By creating them as constants these
function names cannot be declared again for the duration of the process.

Since the prompt function already exists by this time, set the readOnly
flag so to re-declare the prompt requires the use of -force.

It is hoped these changes limit what could be the risk of any script
redefining functions that are called automatically without user intent or
input.
2016-05-12 13:59:33 +01:00

175 lines
5.1 KiB
PowerShell

# Init Script for PowerShell
# Created as part of cmder project
# !!! THIS FILE IS OVERWRITTEN WHEN CMDER IS UPDATED
# !!! Use "%CMDER_ROOT%\config\user-profile.ps1" to add your own startup commands
# We do this for Powershell as Admin Sessions because CMDER_ROOT is not beng set.
if (! $ENV:CMDER_ROOT ) {
$ENV:CMDER_ROOT = resolve-path( $ENV:ConEmuDir + "\..\.." )
}
# Remove trailing '\'
$ENV:CMDER_ROOT = (($ENV:CMDER_ROOT).trimend("\"))
# Compatibility with PS major versions <= 2
if(!$PSScriptRoot) {
$PSScriptRoot = Split-Path $Script:MyInvocation.MyCommand.Path
}
# Add Cmder modules directory to the autoload path.
$CmderModulePath = Join-path $PSScriptRoot "psmodules/"
if( -not $env:PSModulePath.Contains($CmderModulePath) ){
$env:PSModulePath = $env:PSModulePath.Insert(0, "$CmderModulePath;")
}
try {
Get-command -Name "vim" -ErrorAction Stop >$null
} catch {
# # You could do this but it may be a little drastic and introduce a lot of
# # unix tool overlap with powershel unix like aliases
# $env:Path += $(";" + $env:CMDER_ROOT + "\vendor\git-for-windows\usr\bin")
# set-alias -name "vi" -value "vim"
# # I think the below is safer.
new-alias -name "vim" -value $($ENV:CMDER_ROOT + "\vendor\git-for-windows\usr\bin\vim.exe")
new-alias -name "vi" -value vim
}
try {
# Check if git is on PATH, i.e. Git already installed on system
Get-command -Name "git" -ErrorAction Stop >$null
} catch {
$env:Path += $(";" + $env:CMDER_ROOT + "\vendor\git-for-windows\cmd")
# for bash.exe, which in the cmd version is found as <GIT>\usr\bin\bash.exe
$env:Path += $(";" + $env:CMDER_ROOT + "\vendor\git-for-windows\bin")
}
try {
Import-Module -Name "posh-git" -ErrorAction Stop >$null
$gitStatus = $true
} catch {
Write-Warning "Missing git support, install posh-git with 'Install-Module posh-git' and restart cmder."
$gitStatus = $false
}
function checkGit($Path) {
if (Test-Path -Path (Join-Path $Path '.git') ) {
Write-VcsStatus
return
}
$SplitPath = split-path $path
if ($SplitPath) {
checkGit($SplitPath)
}
}
# Load special features come from posh-git
if ($gitStatus) {
Start-SshAgent -Quiet
}
# Move to the wanted location
# This is either a env variable set by the user or the result of
# cmder.exe setting this variable due to a commandline argument or a "cmder here"
if ( $ENV:CMDER_START ) {
Set-Location -Path "$ENV:CMDER_START"
}
if (Get-Module PSReadline -ErrorAction "SilentlyContinue") {
Set-PSReadlineOption -ExtraPromptLineCount 1
}
# Enhance Path
$env:Path = "$Env:CMDER_ROOT\bin;$env:Path;$Env:CMDER_ROOT"
# Drop *.ps1 files into "$ENV:CMDER_ROOT\config\profile.d"
# to source them at startup.
if (-not (test-path "$ENV:CMDER_ROOT\config\profile.d")) {
mkdir "$ENV:CMDER_ROOT\config\profile.d"
}
pushd $ENV:CMDER_ROOT\config\profile.d
foreach ($x in ls *.ps1) {
# write-host write-host Sourcing $x
. $x
}
popd
#
# Prompt Section
# Users should modify their user-profile.ps1 as it will be safe from updates.
#
# Pre assign the hooks so the first run of cmder gets a working prompt.
[ScriptBlock]$PrePrompt = {}
[ScriptBlock]$PostPrompt = {}
[ScriptBlock]$CmderPrompt = {
$Host.UI.RawUI.ForegroundColor = "White"
Microsoft.PowerShell.Utility\Write-Host $pwd.ProviderPath -NoNewLine -ForegroundColor Green
if($gitStatus){
checkGit($pwd.ProviderPath)
}
}
$CmderUserProfilePath = Join-Path $env:CMDER_ROOT "config\user-profile.ps1"
if(Test-Path $CmderUserProfilePath) {
# Create this file and place your own command in there.
. "$CmderUserProfilePath"
} else {
# This multiline string cannot be indented, for this reason I've not indented the whole block
Write-Host -BackgroundColor Darkgreen -ForegroundColor White "First Run: Creating user startup file: $CmderUserProfilePath"
$UserProfileTemplate = @'
# Use this file to run your own startup commands
## Prompt Customization
<#
.SYNTAX
<PrePrompt><CMDER DEFAULT>
λ <PostPrompt> <repl input>
.EXAMPLE
<PrePrompt>N:\Documents\src\cmder [master]
λ <PostPrompt> |
#>
[ScriptBlock]$PrePrompt = {
}
# Replace the cmder prompt entirely with this.
# [ScriptBlock]$CmderPrompt = {}
[ScriptBlock]$PostPrompt = {
}
## <Continue to add your own>
'@
New-Item -ItemType File -Path $CmderUserProfilePath -Value $UserProfileTemplate > $null
}
# Once Created these code blocks cannot be overwritten
Set-Item -Path function:\PrePrompt -Value $PrePrompt -Options Constant
Set-Item -Path function:\CmderPrompt -Value $CmderPrompt -Options Constant
Set-Item -Path function:\PostPrompt -Value $PostPrompt -Options Constant
[ScriptBlock]$Prompt = {
$realLASTEXITCODE = $LASTEXITCODE
PrePrompt | Microsoft.PowerShell.Utility\Write-Host -NoNewline
CmderPrompt
Microsoft.PowerShell.Utility\Write-Host "`nλ " -NoNewLine -ForegroundColor "DarkGray"
PostPrompt | Microsoft.PowerShell.Utility\Write-Host -NoNewline
$global:LASTEXITCODE = $realLASTEXITCODE
return " "
}
# ReadOnly at least requires `-force` to be overwritten
Set-Item -Path function:\prompt -Value $Prompt -Options ReadOnly