Skip to content

Instantly share code, notes, and snippets.

@jinyeow
Last active November 13, 2024 02:24
Show Gist options
  • Save jinyeow/4f51b2f23ae8b90e160877e8a8f29bb5 to your computer and use it in GitHub Desktop.
Save jinyeow/4f51b2f23ae8b90e160877e8a8f29bb5 to your computer and use it in GitHub Desktop.
Pwsh Profile
# gist:4f51b2f23ae8b90e160877e8a8f29bb5
#Requires -Version 7
# === TROUBLESHOOT STARTUP ===
#Set-PSDebug -Trace 1
# Install-Module PSProfiler
# Import-Module PSProfiler
# Measure-Script -Top 3 $profile
# === MODULES ===
# Lazy load modules
$LazyLoadProfileRunspace = [RunspaceFactory]::CreateRunspace()
$LazyLoadProfile = [PowerShell]::Create()
$LazyLoadProfile.Runspace = $LazyLoadProfileRunspace
$LazyLoadProfileRunspace.Open()
[void]$LazyLoadProfile.AddScript({Import-Module posh-git})
[void]$LazyLoadProfile.BeginInvoke()
$null = Register-ObjectEvent -InputObject $LazyLoadProfile -EventName InvocationStateChanged -Action {
Import-Module -Name posh-git
Import-Module -Name PSReadLine
Import-Module -Name PsFzf
$LazyLoadProfile.Dispose()
$LazyLoadProfileRunspace.Close()
$LazyLoadProfileRunspace.Dispose()
}
#Import-Module Az.Tools.Predictor ## Causing issues with tab completion?
# === INSTALLS ===
# NOTE: Uncomment to install the package manager
<#
Install Scoop:
> Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
> irm get.scoop.sh | iex
Install Chocolatey
> Set-ExecutionPolicy Bypass -Scope Process -Force; \
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; \
iex ((New-Object System.Net.WebClient).DownloadString(‘https://community.chocolatey.org/install.ps1'))
#>
# === vi/PSReadLine ===
function OnViModeChange {
if ($args[0] -eq 'Command') {
# Set the cursor to a blinking block
Write-Host -NoNewline "`e[1 q"
} else {
# Set the cursor to a blinking line
Write-Host -NoNewline "`e[5 q"
}
}
if ((Get-Module PSReadLine).Version -lt 2.2) {
throw 'Profile requires PSReadLine 2.2+'
}
$PSReadLineOptions = @{
EditMode = 'Vi'
HistoryNoDuplicates = $true
HistorySearchCursorMovesToEnd = $true
HistorySaveStyle = 'SaveIncrementally'
PredictionSource = 'History'
PredictionViewStyle = 'ListView'
ViModeIndicator = 'Script'
ViModeChangeHandler = $Function:OnViModeChange
}
Set-PSReadLineOption @PSReadLineOptions
Set-PSReadLineKeyHandler -Chord Shift+Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Chord Ctrl+b -Function BackwardChar
Set-PSReadLineKeyHandler -Chord Ctrl+f -Function ForwardChar
Set-PSReadLineKeyHandler -Chord Ctrl+p -Function PreviousHistory
Set-PSReadLineKeyHandler -Chord Ctrl+n -Function NextHistory
Set-PSReadLineKeyHandler -Chord Ctrl+Oem4 -Function ViCommandMode # NOTE: see https://github.com/PowerShell/PSReadLine/issues/906#issuecomment-916847040
Set-PSReadLineKeyHandler -Chord Ctrl+a -Function BeginningOfLine
Set-PSReadLineKeyHandler -Chord Ctrl+e -Function EndOfLine
Set-PSReadLineKeyHandler -Chord Ctrl+w -Function BackwardDeleteWord
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
# === zoxide ===
# For zoxide v0.8.0+
Invoke-Expression (& { (zoxide init powershell | Out-String) })
#$hook = if ($PSVersionTable.PSVersion.Major -lt 6) { 'prompt' } else { 'pwd' }
#(zoxide init --hook $hook powershell | Out-String)
#})
# === PSFzf ===
#Remove-PSReadLineKeyHandler 'Ctrl+r'
#Remove-PSReadLineKeyHandler 'Ctrl+t'
# replace standard tab completion
Set-PSReadLineKeyHandler -Key Tab -ScriptBlock { Invoke-FzfTabCompletion }
Set-PSReadLineKeyHandler -Chord 'alt+f' -ScriptBlock { Invoke-PsFzfRipgrep -SearchString '.' }
Set-PsFzfOption -PSReadlineChordProvider 'Ctrl+f' -PSReadlineChordReverseHistory 'Ctrl+r'
Set-Alias -Name frg -Value Invoke-PsFzfRipgrep
# NOTE: taken from - https://gist.github.com/SteveL-MSFT/a208d2bd924691bae7ec7904cab0bd8e
# === azcli Tab Completion ===
Register-ArgumentCompleter -Native -CommandName az -ScriptBlock {
param($commandName, $wordToComplete, $cursorPosition)
$completion_file = New-TemporaryFile
$env:ARGCOMPLETE_USE_TEMPFILES = 1
$env:_ARGCOMPLETE_STDOUT_FILENAME = $completion_file
$env:COMP_LINE = $wordToComplete
$env:COMP_POINT = $cursorPosition
$env:_ARGCOMPLETE = 1
$env:_ARGCOMPLETE_SUPPRESS_SPACE = 0
$env:_ARGCOMPLETE_IFS = "`n"
$env:_ARGCOMPLETE_SHELL = 'powershell'
az 2>&1 | Out-Null
Get-Content $completion_file | Sort-Object | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)
}
Remove-Item $completion_file, Env:\_ARGCOMPLETE_STDOUT_FILENAME, Env:\ARGCOMPLETE_USE_TEMPFILES, Env:\COMP_LINE, Env:\COMP_POINT, Env:\_ARGCOMPLETE, Env:\_ARGCOMPLETE_SUPPRESS_SPACE, Env:\_ARGCOMPLETE_IFS, Env:\_ARGCOMPLETE_SHELL
}
# === prompt ===
function parse_git_dirty {
$STATUS = "$(git status)"
$output = ''
if ([string]::IsNullOrEmpty($STATUS)) {
$output += '-'
return
} else {
$output += '['
}
if ($STATUS | Select-String -Pattern 'up to date') { $output += '=' }
if ($STATUS | Select-String -Pattern 'branch is ahead') { $output += '>' }
if ($STATUS | Select-String -Pattern 'branch is behind') { $output += '<' }
if ($STATUS | Select-String -Pattern 'renamed:') { $output += 'R' }
if ($STATUS | Select-String -Pattern 'new file:') { $output += '+' }
if ($STATUS | Select-String -Pattern 'Untracked files:') { $output += '?' }
if ($STATUS | Select-String -Pattern 'modified:') { $output += '*' }
if ($STATUS | Select-String -Pattern 'deleted:') { $output += '-' }
if (-not ([string]::IsNullOrEmpty($STATUS))) {
$output += ']'
}
$output
}
function dirtrim {
# truncate the current location if too long
$currentDirectory = $executionContext.SessionState.Path.CurrentLocation.Path
$consoleWidth = [Console]::WindowWidth
$maxPath = [int]($consoleWidth / 3)
if ($currentDirectory.Length -gt $maxPath) {
$parents = $currentDirectory -Split '\\'
$drive = $parents[0]
$leaf = $(Split-Path -Path $currentDirectory -Leaf)
$parent = "$($drive)\"
# Remove the drive and the current directory from list of parent directories
$parents = $($parents | Select-Object -Skip 1 | Select-Object -SkipLast 1)
foreach ($p in $parents) {
$parent += "$($p[0])\"
}
$currentDirectory = "${parent}${leaf}$($color.Reset)"
#$currentDirectory = "`u{2026}" + $currentDirectory.SubString($currentDirectory.Length - $maxPath) + "$($color.Reset)"
}
"$($color.Green)${currentDirectory}"
}
function prompt {
$currentLastExitCode = $LASTEXITCODE
$lastSuccess = $?
$color = @{
Reset = "`e[0m"
Blue = "`e[34;1m"
Red = "`e[31;1m"
Green = "`e[32;1m"
Yellow = "`e[33;1m"
Grey = "`e[37;0m"
White = "`e[37;1m"
Invert = "`e[7m"
RedBackground = "`e[41m"
}
# set color of PS based on success of last execution
if ($lastSuccess -eq $false) {
$lastExit = $color.Red
} else {
$lastExit = $color.Green
}
# get the execution time of the last command
$lastCmdTime = ''
$lastCmd = Get-History -Count 1
if ($null -ne $lastCmd) {
$cmdTime = $lastCmd.Duration.TotalMilliseconds
$units = 'ms'
$timeColor = $color.Green
if ($cmdTime -gt 250 -and $cmdTime -lt 1000) {
$timeColor = $color.Yellow
} elseif ($cmdTime -ge 1000) {
$timeColor = $color.Red
$units = 's'
$cmdTime = $lastCmd.Duration.TotalSeconds
if ($cmdTime -ge 60) {
$units = 'm'
$cmdTIme = $lastCmd.Duration.TotalMinutes
}
}
$lastCmdTime = "$($color.Grey)[$timeColor$($cmdTime.ToString('#.##'))$units$($color.Grey)]$($color.Reset) "
}
# get git branch information if in a git folder or subfolder
$gitBranch = ''
$path = Get-Location
while ($path -ne '') {
if (Test-Path ([System.IO.Path]::Combine($path, '.git'))) {
# need to do this so the stderr doesn't show up in $error
$ErrorActionPreferenceOld = $ErrorActionPreference
$ErrorActionPreference = 'Ignore'
$branch = $(git rev-parse --abbrev-ref --symbolic-full-name '@{u}') -replace 'origin/', ''
$ErrorActionPreference = $ErrorActionPreferenceOld
# handle case where branch is local
if ($lastexitcode -ne 0 -or $null -eq $branch) {
$branch = git rev-parse --abbrev-ref HEAD
}
$branchColor = $color.Yellow
$branchStatus = "$(parse_git_dirty)"
$gitBranch = " $($color.Grey)on $branchColor$branch $($color.Red)$branchStatus$($color.Reset)"
break
}
$path = Split-Path -Path $path -Parent
}
# check if running dev built pwsh
$devBuild = ''
if ($PSHOME.Contains('publish')) {
$devBuild = " $($color.White)$($color.RedBackground)DevPwsh$($color.Reset)"
}
$currentDirectory = dirtrim
$userName = "$($color.Blue)$Env:UserName$($color.Reset)"
"${lastCmdTime}${userName} in ${currentDirectory}${gitBranch}${devBuild}`n${lastExit}PS$($color.Reset)$('>' * ($nestedPromptLevel + 1)) "
$global:LASTEXITCODE = $currentLastExitCode
}
# === STARTUP ===
#if (-Not (Get-Module -ListAvailable -Name Pscx)) {
# Install-Module Pscx -Scope CurrentUser -Force
#}
# === ALIASES ===
if ($PSVersionTable.PSVersion.Major -eq 5) {
Remove-Item alias:wget
Remove-Item alias:curl
}
Set-Alias gcif Get-ChildItem -Force
# === FUNCTIONS ===
Set-Alias -Name g -Value git
function gst {
git status
}
# === Chocolatey profile ===
$ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
if (Test-Path($ChocolateyProfile)) {
Import-Module "$ChocolateyProfile"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment