powershell配置(3)-折腾oh-my-posh和ys主题

1. 安装 oh-my-posh, posh-git

可以用scoop安装:

1
2
# scoop bucket add extras
scoop install oh-my-posh

新建、修改配置文件,运行:

1
2
if (!(Test-Path -Path $PROFILE )) { New-Item -Type File -Path $PROFILE -Force }
code $PROFILE

加入以下内容:

1
2
3
4
5
Import-Module posh-git
Import-Module oh-my-posh
Set-Theme Paradox
# 如果PowerShell设置里找不到字体,加上下面这一行
# chcp 65001

ref: https://github.com/JanDeDobbeleer/oh-my-posh/

2. 设置字体

然后把字体设置为更纱黑体,就基本看起来比较舒服了。

也可以用其他的字体,去这里找: https://github.com/ryanoasis/nerd-fonts

但是我并不想用这些字体

3. 继续瞎折腾: 自定义一个oh-my-posh主题

3.1 特殊字符代替

使用YaHei Consolas Hybrid等非powerline字体,遇到了缺失字符的问题,那就干脆找出来 oh-my-posh 究竟用了那些特殊字符?

1
2
3
4
5
6
7
8
9
10
# 显示当前主题设置
$themesettings

# 显示当前主题用到的字符
$themesettings.promptsymbols
$themesettings.gitsymbols

# 显示当前主题用到的颜色
Show-ThemeColors # 用到的颜色
Show-Colors # 所有颜色

还可以暴力搜索所有主题文件里的特殊字符(python代码在后面),

最后发现里涉及到的特殊字符如下(后面3个字符是我自己加上的):

关于 unicode 字符的查询可以到这里:

https://unicode-table.com/cn/
https://apps.timwhitlock.info/unicode/inspect/

那么我们可以把一些特殊字符改为一些常见的字符或者字体中已包含的字符:

名称 default ys jetbrains 备注
首字符 #, ➜ # # StartSymbol
普通用户指示符 ▶, ❯ % > PromptIndicator
管理员指示符 $ PromptIndicator
版本分支符号 BranchSymbol
版本状态:一致 o BranchIdenticalStatusToSymbol
版本状态:未监视 x BranchUntrackedSymbol
上一命令执行错误 ⨯, ✗ ? FailedCommandSymbol

3.2 自定义posh主题(仿ys主题)

本主题已被加入官方库,Set-Theme ys即可使用

新建主题文件,code C:\Users\xxxx\Documents\WindowsPowerShell\PoshThemes\ys-like.psm1, 写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

#requires -Version 2 -Modules posh-git

function Write-Theme {
param(
[bool]
$lastCommandFailed,
[string]
$with
)
# check the last command state and indicate if failed
If ($lastCommandFailed) {
$prompt += Write-Prompt -Object "$($sl.PromptSymbols.FailedCommandSymbol) " -ForegroundColor $sl.Colors.CommandFailedIconForegroundColor
}
# write # and space
$prompt = Write-Prompt -Object $sl.PromptSymbols.StartSymbol -ForegroundColor $sl.Colors.PromptSymbolColor
# write user and host
$user = $sl.CurrentUser
if (Test-NotDefaultUser($user)) {
$prompt += Write-Prompt -Object " $user" -ForegroundColor $sl.Colors.PromptHighlightColor
# write at (devicename)
$computer = $sl.CurrentHostname
$prompt += Write-Prompt -Object " at" -ForegroundColor $foregroundColor
$prompt += Write-Prompt -Object " $computer" -ForegroundColor $sl.Colors.PromptForegroundColor
# write in for folder
$prompt += Write-Prompt -Object " in" -ForegroundColor $foregroundColor
}
# write folder
$dir = Get-FullPath -dir $pwd
$prompt += Write-Prompt -Object " $dir " -ForegroundColor $sl.Colors.GitDefaultColor
# write on (git:branchname status)
$status = Get-VCSStatus
if ($status) {
$themeInfo = Get-VcsInfo -status ($status)
$prompt += Write-Prompt -Object 'on git:' -ForegroundColor $foregroundColor
$prompt += Write-Prompt -Object "$($themeInfo.VcInfo) " -ForegroundColor $sl.Colors.GitForegroundColor
}
# write [time]
$timeStamp = Get-Date -Format T
$prompt += Write-Prompt "[$timeStamp]" -ForegroundColor $foregroundColor
# new line
$prompt += Set-Newline
if (Test-Administrator) {
$prompt += Write-Prompt -Object ($sl.PromptSymbols.ElevatedSymbol + " ") -ForegroundColor $sl.Colors.AdminIconForegroundColor
}
else{
$prompt += Write-Prompt -Object ($sl.PromptSymbols.PromptIndicator + " ") -ForegroundColor $sl.Colors.PromptSymbolColor
}
}

$sl = $global:ThemeSettings # local settings
$sl.PromptSymbols.StartSymbol = '#'
$sl.PromptSymbols.PromptIndicator = '%'
$sl.PromptSymbols.ElevatedSymbol = '$'
$sl.GitSymbols.BranchSymbol = ''
$sl.GitSymbols.BranchUntrackedSymbol = 'x'
$sl.GitSymbols.BranchIdenticalStatusToSymbol = 'o'
$sl.PromptSymbols.FailedCommandSymbol = '?'

# for dark theme
$sl.Colors.AdminIconForegroundColor = [ConsoleColor]::Red
$sl.Colors.PromptSymbolColor = [ConsoleColor]::Blue
$sl.Colors.PromptForegroundColor = [ConsoleColor]::Green
$sl.Colors.PromptHighlightColor = [ConsoleColor]::Cyan
$sl.Colors.GitDefaultColor = [ConsoleColor]::Yellow
$sl.Colors.GitForegroundColor = [ConsoleColor]::Cyan

# inspired by ys theme: not to use special characters (powerline fonts).
# > https://blog.ysmood.org/my-ys-terminal-theme/

效果如下:


PS. 找出 oh-my-posh 用到的特殊字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#%% 找出 `oh-my-posh` 用到的特殊字符
import os, re

def get_posh_symbols(root):
# 找到所有配置文件
files = []
# - 默认配置文件
default_file = os.path.join(root, 'defaults.ps1')
files.append(default_file)

# - 主题配置文件
themes_dir = os.path.join(root, 'Themes')
for parent, dirnames, filenames in os.walk(themes_dir):
for filename in filenames:
filedir = os.path.join(parent, filename)
files.append(filedir)
print('All config files:\n ', '\n '.join(files))

# 找到所有可能的 powerline 字符
symbols = []
for file in files:
with open(file, 'r', encoding='utf8') as f:
res = f.read(50000)
chars = re.findall("0x[0-9A-F]{4}", res)
symbols.extend(chars)
# - 去掉重复的,排序
symbols = sorted(list(set(symbols)))
# - 打印
for i in posh_symbols:
print(f'{ i:8s} {chr(int(i, base=16)):4s}')

return symbols

posh_root = r'C:\Users\xxxx\scoop\apps\oh-my-posh\current'
posh_symbols = get_posh_symbols(posh_root)


#%% 显示 powerline 字符
from PIL import Image,ImageDraw,ImageFont

ttfont = ImageFont.truetype("JetBrainsMono-Regular.ttf", 16)

dict = {'0x00BB': 'Right-Pointing Double Angle Quotation Mark',
'0x2191': 'Upwards Arrow',
'0x2193': 'Downwards Arrow',
'0x2262': 'Not Identical To',
'0x2263': 'Strictly Equivalent To',
'0x250C': 'Box Drawings Light Down And Right',
'0x2514': 'Box Drawings Light Up And Right',
'0x25B6': 'Black Right-Pointing Triangle',
'0x25F7': 'White Circle With Upper Right Quadrant',
'0x26A1': 'High Voltage Sign',
'0x276F': 'Heavy Right-Pointing Angle Quotation Mark Ornament',
'0x279C': 'Heavy Round-Tipped Rightwards Arrow',
'0x2A2F': 'Vector Or Cross Product',
'0xE0A0': 'Version Control Branch',
'0xE0A1': 'LN (line) Symbol',
'0xE0A2': 'Closed Padlock',
'0xE0B0': 'Rightwards Black Arrowhead',
'0xE0B1': 'Rightwards Arrowhead',
'0xE0B2': 'Leftwards Black Arrowhead',
'0xE0B3': 'Leftwards Arrowhead',
'0xE606': 'Python Logo',
'0xF09B': 'Github Logo',
'0xF171': 'Bitbucket Logo',
'0xF296': 'GitLab Logo',
'0x0000': '',
'0x27E9': 'Mathematical Right Angle Bracket',
'0x2260': 'Not Equal To',
'0x2261': 'Identical To',
'0x2717': 'BALLOT X'
}

def show_posh_fonts():
im = Image.new('RGBA', (600, 600), (255, 255, 255))
draw = ImageDraw.Draw(im)

txt = '\n'.join([f'{i} {chr(int(i, base=16))} {dict[i]}' for i in dict])
print(txt)

draw.text((5,5), txt, fill=(0,0,0),font=ttfont)
im.show()

show_posh_fonts()


#%% 打印所有 unicode 字符
from PIL import Image, ImageDraw, ImageFont

ttfont = ImageFont.truetype("JetBrainsMono-Regular.ttf", 16)

def show_all_fonts(list):
im = Image.new('RGBA', (1600, 800), (255, 255, 255))

for st, x, y in list:
txt = ''
for i in range(st, st + 0x0100):
if i % 16 == 0:
txt += f'\n {hex(i):6s} '
txt += f'{chr(i):2s}'
print(txt)

draw = ImageDraw.Draw(im)
draw.text((x, y+20), txt, fill=(0,0,0),font=ttfont)
im.show()

list = [[0x2100, 0, 0],
[0x2200, 400, 0],
[0x2300, 800, 0],
[0x2400, 1200, 0],
[0x2500, 0, 400],
[0x2600, 400, 400],
[0x2700, 800, 400],
[0xE000, 1200, 400],
]

show_all_fonts(list)

# %%