Skip to content

Instantly share code, notes, and snippets.

@brehaut
Last active November 3, 2024 19:45
Show Gist options
  • Save brehaut/25d0e065a14c9fd2f4f9d495fad4f11a to your computer and use it in GitHub Desktop.
Save brehaut/25d0e065a14c9fd2f4f9d495fad4f11a to your computer and use it in GitHub Desktop.
JJ aware powershell prompt

jj Aware Powershell Prompt

This is a simple script to create a nice powershell prompt with jj version control integration.

Path names are abbreviated approximately like fish does out of the box, and $HOME is abbreviated to ~. The VCS information appears on the far right when in a jj repository.

Window/tab title is set to the working directory, or, if in a jj repository, the jj root name.

The format for VCS information is derived from hroi’s fish prompt

function JJPrompt() {
if (-not (Get-Command jj -errorAction SilentlyContinue)) {
return
}
$root = (jj root --quiet 2> $null)
if (-not $root) {
return
}
$status = jj log --ignore-working-copy --no-graph --color always -r `@ -T '
separate(
" ",
bookmarks.join(", "),
coalesce(
surround(
"\"",
"\"",
if(
description.first_line().substr(0, 24).starts_with(description.first_line()),
description.first_line().substr(0, 24),
description.first_line().substr(0, 23) ++ "…"
)
),
"(no description)"
),
change_id.shortest(),
commit_id.shortest(),
if(conflict, "(conflict)"),
if(empty, "(empty)"),
if(divergent, "(divergent)"),
if(hidden, "(hidden)"),
)
'
return $status #.Replace("UΓǪ", "…") # Theres some encoding weirdness going on with ellipsis. Patch in this fix
}
function setTitle() {
$root = [System.IO.Path]::GetFileNameWithoutExtension($(jj root --quiet)) 2> $null
if ($root) {
$host.UI.RawUI.WindowTitle = "jj: $root";
}
else {
$host.UI.RawUI.WindowTitle = [System.IO.Path]::GetFileNameWithoutExtension($pwd)
}
}
function PathList($path) {
$list = New-Object Collections.Generic.List[String]
$remainder = $path
while ($null -ne $remainder) {
$fn = [System.IO.Path]::GetFileName($remainder)
if ($fn) {
$list.Add($fn)
}
$remainder = [System.IO.Path]::GetDirectoryName($remainder)
}
$root = [System.IO.Path]::GetPathRoot($path);
if ($root) {
$list.Add($root)
}
$list.Reverse()
return $list
}
function AbbreviatedPath($path) {
$rawSegments = PathList $path
if (($rawSegments.Count) -lt 3) {
return $path
}
$abbreviated = New-Object Collections.Generic.List[string]
$abbreviated.Add($rawSegments[0])
foreach ($segment in $rawSegments[1..($rawSegments.Count - 2)]) {
$abbreviated.Add($segment[0])
}
$abbreviated.Add($rawSegments[-1]);
return [System.IO.Path]::Combine($abbreviated)
}
function writeRight($message, $color) {
$foreColor = $host.ui.RawUI.ForegroundColor
$cur = $Host.UI.RawUI.CursorPosition
$length = ($message -replace '\x1b\[\d+(;\d+)*m').Length
$startposx = $Host.UI.RawUI.windowsize.width - $length
$startposy = $Host.UI.RawUI.CursorPosition.Y
$Host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates $startposx,$startposy
$host.UI.RawUI.ForegroundColor = $color
$Host.UI.Write($message)
# reset cursor and color
$host.UI.RawUI.ForegroundColor = $foreColor
$Host.UI.RawUI.CursorPosition = $cur
}
$Global:PromptTerminator = "▷"
function Global:prompt {
setTitle
$foreColor = $host.ui.RawUI.ForegroundColor
$host.UI.RawUI.ForegroundColor = "Yellow"
$Host.UI.Write((AbbreviatedPath ([string]$pwd).Replace($HOME, "~")))
writeRight (JjPrompt) "Gray"
$host.UI.RawUI.ForegroundColor = $foreColor
$Host.UI.Write(" $($global:PromptTerminator ?? ">")")
return " "
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment