Skip to content

Instantly share code, notes, and snippets.

@Gravifer
Last active July 28, 2026 11:33
Show Gist options
  • Select an option

  • Save Gravifer/7b27c219fed8f79cbdf1a2d123fac312 to your computer and use it in GitHub Desktop.

Select an option

Save Gravifer/7b27c219fed8f79cbdf1a2d123fac312 to your computer and use it in GitHub Desktop.
Git & Jujutsu aware oh-my-posh theme, based on the built-in "tokyo"
if ($global:GraviferMainWorktreeCache -isnot [hashtable]) {
$global:GraviferMainWorktreeCache = @{}
}
function global:Set-GraviferPoshContext {
param([bool]$originalStatus)
Remove-Item -LiteralPath 'Env:GRAVIFER_MAIN_WORKTREE' -ErrorAction SilentlyContinue
$location = Get-Location
if ($location.Provider.Name -ne 'FileSystem') {
return
}
$directory = [System.IO.DirectoryInfo]::new($location.ProviderPath)
while ($null -ne $directory) {
$dotGit = [System.IO.Path]::Combine($directory.FullName, '.git')
if ([System.IO.Directory]::Exists($dotGit)) {
return
}
if ([System.IO.File]::Exists($dotGit)) {
try {
$gitDirLine = [System.IO.File]::ReadAllText($dotGit).Trim()
if (-not $gitDirLine.StartsWith('gitdir:', [System.StringComparison]::OrdinalIgnoreCase)) {
return
}
$gitDirValue = $gitDirLine.Substring(7).Trim()
if ([System.IO.Path]::IsPathRooted($gitDirValue)) {
$gitDir = [System.IO.Path]::GetFullPath($gitDirValue)
}
else {
$gitDir = [System.IO.Path]::GetFullPath(
[System.IO.Path]::Combine($directory.FullName, $gitDirValue)
)
}
$commonDirFile = [System.IO.Path]::Combine($gitDir, 'commondir')
if (-not [System.IO.File]::Exists($commonDirFile)) {
return
}
if (-not $global:GraviferMainWorktreeCache.ContainsKey($gitDir)) {
$mainWorktree = ''
$worktreeOutput = & git -C $directory.FullName worktree list --porcelain -z 2>$null
if ($LASTEXITCODE -eq 0) {
$outputText = $worktreeOutput -join ''
$firstWorktree = $outputText -split "`0" |
Where-Object { $_.StartsWith('worktree ', [System.StringComparison]::Ordinal) } |
Select-Object -First 1
if ($null -ne $firstWorktree) {
$mainWorktree = $firstWorktree.Substring(9)
}
}
$global:GraviferMainWorktreeCache[$gitDir] = $mainWorktree
}
$cachedMainWorktree = $global:GraviferMainWorktreeCache[$gitDir]
if (-not [string]::IsNullOrEmpty($cachedMainWorktree)) {
$env:GRAVIFER_MAIN_WORKTREE = $cachedMainWorktree
}
}
catch {
return
}
return
}
$directory = $directory.Parent
}
}
Set-Alias -Name Set-PoshContext -Value Set-GraviferPoshContext -Scope Global -Force
{
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
"palette": {
"jujutsu-change-id": "#e3e50a",
"jujutsu-change-id-rest": "darken(p:jujutsu-change-id, 35)"
},
"blocks": [
{
"alignment": "left",
"leading_diamond": "<#7eb8da>\u250f</>",
"segments": [
{
"foreground": "#7eb8da",
"properties": {
"time_format": "2006/01/02 15:04:05"
},
"style": "diamond",
"template": "[<#ffffff>\uf073</> {{ .CurrentDate | date .Format }}]",
"type": "time"
},
{
"foreground": "#7eb8da",
"style": "plain",
"template": "[<#ffffff>\ueb99</> {{ .UserName }} :: <#ffffff>\uf108</> {{ .HostName }}]",
"type": "session"
},
{
"foreground": "#be9ddf",
"style": "diamond",
"template": "[<#ffffff>\ue266</> RAM: {{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB]",
"type": "sysinfo"
},
{
"foreground": "#f36943",
"foreground_templates": [
"{{if eq \"Charging\" .State.String}}#40c4ff{{end}}",
"{{if eq \"Discharging\" .State.String}}#ff5722{{end}}",
"{{if eq \"Full\" .State.String}}#4caf50{{end}}"
],
"properties": {
"charged_icon": "<#ffffff>\ue22f</> ",
"charging_icon": "\ueb2d ",
"discharging_icon": "<#ffff00>\uf244</> "
},
"style": "plain",
"template": "[{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\uf295]",
"type": "battery"
},
{
"foreground": "#be9ddf",
"properties": {
"style": "dallas",
"threshold": 0
},
"style": "diamond",
"template": "[<#ffffff>\uf252</> {{ .FormattedMs }}s]",
"type": "executiontime"
}
],
"type": "prompt"
},
{
"alignment": "left",
"newline": true,
"leading_diamond": "<#7eb8da>\u2523</>",
"segments": [
{
"foreground": "#7eb8da",
"style": "diamond",
"template": "[<#ffffff>\uebd8</> Subscription: <#ffff00>{{ .Name }}</>]",
"type": "az"
},
{
"foreground": "#7eb8da",
"style": "diamond",
"template": "[<#ffffff>\uebd8</> Azure Developer CLI Environment: <#ffff00>{{ .DefaultEnvironment }}</> :: <#ffff00>{{ .Version }}</>]",
"type": "azd"
},
{
"foreground": "#7eb8da",
"style": "diamond",
"template": "[<#ffffff>\uf270</> <#ffff00>{{ .Profile }}</>{{if .Region}}@<#ffff00>{{ .Region }}</>{{ end }}]",
"type": "aws"
},
{
"foreground": "#7eb8da",
"style": "diamond",
"template": "[{{ if .Error }}{{ .Error }}{{ else }}<#ffffff>\uf1a0</> <#ffff00>{{ .Project }}</> :: <#ffff00>{{.Account}}</>{{ end }}]",
"type": "gcp"
},
{
"foreground": "#ffa5d8",
"style": "diamond",
"template": "[<#ffffff>\uf10fe</> <#ffff00>{{.Context}}</>{{if .Namespace}} :: <#ffff00>{{.Namespace}}</>{{end}}]",
"type": "kubectl"
},
{
"foreground": "#ffa5d8",
"style": "diamond",
"template": "[{{ if .Error }}{{ .Error }}{{ else }}{{ if .Name }}<#ffffff>\uf487</> {{ .Name }}{{ end }}{{ if .Target }} {{ .Target }}{{ end }}{{ end }}]",
"type": "project"
}
],
"type": "prompt"
},
{
"alignment": "left",
"newline": true,
"leading_diamond": "<#7eb8da>\u2523</>",
"segments": [
{
"foreground": "#7eb8da",
"properties": {
"folder_separator_icon": "/",
"style": "full"
},
"style": "diamond",
"template": "[<#ffffff>\uf115</> <#98bfad>{{ $raw := .$.AbsolutePWD }}{{ $full := .Path }}{{ if hasPrefix \"\\\\\\\\\" $raw }}{{ $raw }}{{ else if not (.Segments.Contains \"Git\") }}{{ $full }}{{ else }}{{ $git := .Segments.Git }}{{ $rel := replace \"\\\\\" \"/\" $git.RelativeDir }}{{ if or (eq $rel \"\") (le (len (splitList \"\" $full)) 52) }}{{ $full }}{{ else }}{{ $parts := splitList \"/\" $full }}{{ $relParts := splitList \"/\" $rel }}{{ $repoIndex := sub (len $parts) (add (len $relParts) 1) }}{{ if lt $repoIndex 1 }}{{ $full }}{{ else }}{{ $root := index $parts 0 }}{{ $repo := index $parts $repoIndex }}{{ $base := printf \"%s/%s\" $root $repo }}{{ if eq $repoIndex 2 }}{{ $base = printf \"%s/%s/%s\" $root (index $parts 1) $repo }}{{ else if gt $repoIndex 2 }}{{ $base = printf \"%s/%s/\u2026/%s\" $root (index $parts 1) $repo }}{{ end }}{{ if eq (len $relParts) 1 }}{{ $base }}/{{ index $relParts 0 }}{{ else }}{{ $firstRel := index $relParts 0 }}{{ $remainingCount := int (sub (len $relParts) 1) }}{{ $tail := list }}{{ $locked := false }}{{ range $i := untilStep (int (sub (len $relParts) 1)) 0 -1 }}{{ if not $locked }}{{ $candidate := prepend $tail (index $relParts $i) }}{{ $candidatePath := printf \"%s/%s/\u2026/%s\" $base $firstRel (join \"/\" $candidate) }}{{ if eq (len $candidate) $remainingCount }}{{ $candidatePath = printf \"%s/%s/%s\" $base $firstRel (join \"/\" $candidate) }}{{ end }}{{ if or (eq (len $tail) 0) (le (len (splitList \"\" $candidatePath)) 52) }}{{ $tail = $candidate }}{{ else }}{{ $locked = true }}{{ end }}{{ end }}{{ end }}{{ if eq (len $tail) $remainingCount }}{{ $base }}/{{ $firstRel }}/{{ join \"/\" $tail }}{{ else }}{{ $base }}/{{ $firstRel }}/\u2026/{{ join \"/\" $tail }}{{ end }}{{ end }}{{ end }}{{ end }}{{ end }}</>]",
"type": "path"
},
{
"foreground": "#ffa5d8",
"properties": {
"change_id_min_len": 8,
"fetch_status": true,
"ignore_working_copy": true
},
"style": "plain",
"template": "{{ $hasGit := .Segments.Contains \"Git\" }}[<#ffffff>{{ if $hasGit }}{{ trim .Segments.Git.UpstreamIcon }}{{ else }}\ue5fb{{ end }} </><p:jujutsu-change-id>({{ .ChangeIDPrefix }}</><p:jujutsu-change-id-rest>{{ .ChangeIDRest }}</><p:jujutsu-change-id>{{ if .Working.Changed }}{{ if not $hasGit }} {{ .Working.String }}{{ else }}{{ $git := .Segments.Git }}{{ if and (not $git.Working.Changed) (not $git.Staging.Changed) }} {{ .Working.String }}{{ end }}{{ end }}{{ end }})</>{{ if $hasGit }} {{ else }}]{{ end }}",
"type": "jujutsu"
},
{
"foreground": "#ffa5d8",
"properties": {
"fetch_stash_count": true,
"fetch_status": true,
"fetch_upstream_icon": true
},
"style": "plain",
"template": "{{ if not (.Segments.Contains \"Jujutsu\") }}[<#ffffff>{{ .UpstreamIcon }} </>{{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if and .IsWorkTree .Env.GRAVIFER_MAIN_WORKTREE }} <#ffffff>\udb81\udcc1</> <#98bfad>{{ .Env.GRAVIFER_MAIN_WORKTREE }}</>{{ end }}{{ if .Working.Changed }} <#ffffff>\uf044</> {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} <#ffffff>\uf046</> {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} <#ffffff>\ueb4b</> {{ .StashCount }}{{ end }}]",
"type": "git"
}
],
"type": "prompt"
},
{
"alignment": "left",
"newline": true,
"leading_diamond": "<#7eb8da>\u2514\u2500</>",
"segments": [
{
"style": "diamond",
"template": "<#ffff00>[#]</>",
"type": "root"
},
{
"foreground": "#ffa5d8",
"style": "diamond",
"template": "[<#ffffff>\uea6c</> Error]",
"type": "status"
},
{
"style": "diamond",
"template": ">",
"type": "text"
}
],
"type": "prompt"
}
],
"final_space": true,
"secondary_prompt": {
"background": "transparent",
"template": " "
},
"valid_line": {
"background": "transparent",
"template": "> "
},
"error_line": {
"background": "transparent",
"template": "<#ff0000>\uea87</> "
},
"version": 3
}
# Import-Module 'C:\tools\vcpkg\scripts\posh-vcpkg'
# Import-Module 'C:\ProgramData\chocolatey\lib\bottom\tools\completion\_btm.ps1'
Import-Module "$env:USERPROFILE\anaconda3\shell\condabin\conda-hook.ps1" # conda activate # Import-Module 'C:\ProgramData\Anaconda3\shell\condabin\conda-hook.ps1'
function y { # https://yazi-rs.github.io/docs/quick-start#shell-wrapper
$tmp = (New-TemporaryFile).FullName
yazi $args --cwd-file="$tmp"
$cwd = Get-Content -Path $tmp -Encoding UTF8
if (-not [String]::IsNullOrEmpty($cwd) -and $cwd -ne $PWD.Path) {
Set-Location -LiteralPath (Resolve-Path -LiteralPath $cwd).Path
}
Remove-Item -Path $tmp
}
Import-Module "$env:USERPROFILE\Documents\PowerShell\Moonbit.PwshShellCompletion.ps1"
Import-Module "$env:USERPROFILE\Documents\PowerShell\Rustup.PwshCompletions.ps1"
# oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH/gravifer-tokyo.omp.json" | Invoke-Expression
oh-my-posh init pwsh --config "$env:USERPROFILE/.config/oh-my-posh/gravifer-tokyo.omp.json" | Invoke-Expression
. "$env:USERPROFILE/.config/oh-my-posh/gravifer-tokyo.context.ps1"
Invoke-Expression (& { (zoxide init powershell | Out-String) })
Invoke-Expression (&scoop-search --hook)
function git-bash {
& "C:\\Program Files\\Git\\bin\\bash.exe"
}
(& opam env) -split '\r?\n' | ForEach-Object { Invoke-Expression $_ }
Invoke-Expression (& { (jj util completion power-shell | Out-String) })
$OutputEncoding = [Console]::OutputEncoding = [Text.Encoding]::UTF8
. '~\AppData\Roaming\dystroy\broot\config\launcher\powershell\br.ps1'
@Gravifer

Copy link
Copy Markdown
Author

Just a provisional working theme. Screenshots, behavior notes, installation context, and the upstream improvements it motivated are documented in the Oh My Posh Themes Discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment