Icing out my Powershell
Introduction
A Professor of mine from college introduced me to a new religion, Powershell 7
Before it, I had been using git bash for Windows. It’s POSIX compliant, lightweight - startup goes brrrr -, runs bash scripts really well(on windows!), works on VSCode and integrates really well with git
I know the last part seems obvious, but I still haven’t figured out how it autocompletes branch names
For the longest time I had sworn by git bash for Windows - yes, I will keep on using its full name… I miss it - but the more I used, the more it reminded me it’s not a drop-in replacement for Powershell
I couldn’t use sudo
for escalating privileges, same
uvicorn commands that work on powershell becomes
slobs of error tests, there were no split tabs and most importantly, there
wasn’t any system level package manager
So when my use of WSL and VMs with Linux distros dumbed down what I needed from
git bash for Windows to scripts that could
run on Powershell - python -m <insert script here>
- I made the final switch
I changed my default terminal on VSCode to Powershell
Since then, I may or may not have occasionally
$touch
’ed my files expecting a response
Being the sentimental person I am, I decided to ice out my Powershell with huge
inspiration from git’s .bashrc
The icing
Window Name
Imagine, 3 hours into the morning, no sleep, half drank coffee and you’re so close to solving a very nasty bug
You have your eureka moment, about to test out the command, but then you stop,
because you have 10 powershell tabs open and they’re all named Powershell
,
let’s just hope the idea stays while you figure out which tab is which or give
up, and start recalling the file path to the script you were working on
I had that moment - wayy less dramatic - so I decided to name my window the path to the file I am on. I know, innovative
Before
After
Theme
Having an all white theme going on ended up being a constant reminder I was on powershell, and I didn’t need that, so I took the colors from git bash and applied it to my powershell redesign
Git User
The next thing I needed from my terminal was something a bit more dear to me.
I had already worked on a script that gave me the ability to switch git users
cleanly, but I have a habit of forgetting which user I am on, and an even worse
habit of forgetting to switch. So I added a little text to remind me
Git branch
A lot like my username, I also had a habit of forgetting which branch I was in, so I added a branch name cos why not?
Repo State
This was most definitely me nerd sniping myself. I always wondered if I could know at any point if I have uncommited changes, commits to be pushed or if I’m behind from my origin repo. I mean VScode’s source control tab does it, so I prompted the hell out of chatgpt and got something that works
And that led to this beauty
Extra
I also added the little $
for users and #
for admins cos nostalgia, and I
removed the PS
prefix powershell add, which I really hope meant “powershell”,
but if it didn’t then it definitely didn’t do its job
PROFILE
All that led to the script below you can add to your $PROFILE
file
function prompt {
$userName = git config --global user.name 2>$null
$branch = ''
$isDirty = $false
try {
$branch = git rev-parse --abbrev-ref HEAD 2>$null
$status = git status --porcelain 2>$null
if ($status) {
$isDirty = $true
}
} catch {}
$cwd = (Get-Location).Path
$width = $Host.UI.RawUI.WindowSize.Width
$isAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
[Security.Principal.WindowsBuiltInRole]::Administrator)
$promptChar = if ($isAdmin) { "#" } else { "$" }
$host.UI.RawUI.WindowTitle = $cwd
$gitFlag = ""
$isSynced = $true
if (Test-Path .git) {
try {
$local = git rev-parse "@"
$remote = git rev-parse "@{u}" 2>$null
$base = git merge-base "@" "@{u}"
if ($remote -and $base -and $local -ne $remote) {
$isSynced = $false
if ($local -eq $base) {
$gitFlag = "↓"
} elseif ($remote -eq $base) {
$gitFlag = "↑"
} else {
$gitFlag = "⇵"
}
}
} catch {
# If upstream doesn't exist, ignore
}
}
# Construct right block
$left = $cwd
$baseRight = if ($branch) { "[${userName}:${branch}" } else { "[${userName}" }
$dirtySymbol = if ($isDirty) { "*" } else { "" }
$closingBracket = "]"
# Calculate padding
$rightTextLength = ($baseRight + $dirtySymbol + $gitFlag + $closingBracket).Length
$padding = $width - ($left.Length + $rightTextLength)
if ($padding -lt 1) {
$left = '...' + $left.Substring($left.Length - ($width - $rightTextLength - 4))
$padding = 1
}
$spaces = ' ' * $padding
# Colors
$darkGreen = "DarkGreen"
$muted = "DarkGray"
$dirtyColor = "Red" # or "Yellow" or "Magenta"
$promptColor = "White"
Write-Host "$left$spaces" -NoNewline -ForegroundColor $darkGreen
Write-Host "$baseRight" -NoNewline -ForegroundColor $muted
if ($isDirty) {
Write-Host "$dirtySymbol" -NoNewline -ForegroundColor $dirtyColor
}
if ($isSynced -eq $false) {
Write-Host "$gitFlag" -NoNewline -ForegroundColor $dirtyColor
}
Write-Host "$closingBracket" -ForegroundColor $muted
Write-Host "$promptChar" -NoNewline -ForegroundColor $promptColor
return ' '
}
Conclusion
I really love how my powershell turned out. The colors, the window name, and the extra git info stuffed at the side blend really well into the background until I absolutely need them and personally that’s what I was going for
Good design is obvious. Great design is transparent.
Joe Sparano
Author’s note
I’ve heard of terminal emulators, and I plan on checking them out, but for now, I am getting a lot more comfy with powershell, and I love having both python and Vim managed by the same package manager, rather than having 10 different sources, an install manual with bash, and a convuluted path variable to navigate
I also dedicated the ~/Scripts
folder for all my system-wide custom scripts, and not to
brag but I have two!