docs: add PowerShell terminal enhancement guide with PSFzf and Starship

补充完整的PowerShell终端增强配置教程,包括PSFzf安装配置、分版本的PS7+/5.1终端配置、Starship Catppuccin主题配置、快捷键速查和常见问题解答
This commit is contained in:
wenyongda 2026-06-03 15:36:14 +08:00
parent c8369483b3
commit a12e1365d6

View File

@ -121,6 +121,730 @@ PowerShellGet\Install-Module posh-git -Scope CurrentUser -Force
Install-Module PSReadLine -Force Install-Module PSReadLine -Force
``` ```
### [PSFzf](https://github.com/kelleymaureen/PSFzf)
> [PSFzf](https://github.com/kelleymaureen/PSFzf) 是 fzf 的 PowerShell 集成模块,提供模糊搜索历史命令和文件功能。
```powershell
# 安装 PSFzf 模块
Install-Module PSFzf -Scope CurrentUser -Force
# 安装 fzf 本体PSFzf 的底层依赖)
winget install junegunn.fzf
```
## 终端增强配置Starship + PSReadLine
> 参考:[PowerShell 终端增强配置指南](https://mp.weixin.qq.com/s/DV-T4Tr4KaonFdgutuzhQQ)
### 前置准备
#### 确认 PowerShell 版本
```powershell
$PSVersionTable.PSVersion
```
- 主版本号为 `5` → 使用 **PS5.1 方案**
- 主版本号为 `7` → 使用 **PS7+ 方案**
#### 确认 Profile 文件路径
```powershell
# 查看路径
echo $PROFILE
# 若文件不存在则创建
if (!(Test-Path $PROFILE)) {
New-Item -ItemType File -Path $PROFILE -Force
}
# 用 VSCode 打开编辑
code $PROFILE
```
> PS5.1 的 Profile 路径通常为:`C:\Users\<用户名>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`
>
> PS7+ 的 Profile 路径通常为:`C:\Users\<用户名>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1`
>
> 两个版本的 Profile **互相独立**,需分别配置。
#### 设置执行策略(如遇权限报错)
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
### 一次性安装依赖
#### PowerShell 7+ 安装依赖
```powershell
# 1. 信任 PSGallery
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
# 2. 安装最新版 PSReadLine
Install-Module PSReadLine -Force -Scope CurrentUser
# 3. 安装 posh-git
Install-Module posh-git -Scope CurrentUser -Force
# 4. 安装 PSFzf
Install-Module PSFzf -Scope CurrentUser -Force
# 5. 安装 fzf 本体
winget install junegunn.fzf
```
#### PowerShell 5.1 安装依赖
```powershell
# 1. 信任 PSGallery
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
# 2. 安装 PSReadLinePS5.1 最高兼容 2.3.x必须指定版本
Install-Module PSReadLine -RequiredVersion 2.3.4 -Force -Scope CurrentUser -SkipPublisherCheck
# 3. 安装 posh-git
Install-Module posh-git -Scope CurrentUser -Force
# 4. 安装 PSFzf
Install-Module PSFzf -Scope CurrentUser -Force
# 5. 安装 fzf 本体
winget install junegunn.fzf
```
### Starship 配置
Starship 是跨平台的提示符工具,支持 Windows、Linux、macOS。
#### 安装 Starship
```powershell
winget install --id Starship.Starship
```
#### 配置文件位置
Windows 下配置文件路径:`~/.config/starship.toml`
```powershell
# 创建配置目录和文件
mkdir -p ~/.config
New-Item -Path ~/.config/starship.toml -ItemType File -Force
# 用 VSCode 打开编辑
code ~/.config/starship.toml
```
#### 完整配置Catppuccin Mocha 主题)
将以下内容粘贴到 `starship.toml` 文件中:
```toml
"$schema" = 'https://starship.rs/config-schema.json'
format = """
[](red)\
$os\
$username\
[](bg:peach fg:red)\
$directory\
[](bg:yellow fg:peach)\
$git_branch\
$git_status\
[](fg:yellow bg:green)\
$c\
$rust\
$golang\
$nodejs\
$bun\
$php\
$java\
$kotlin\
$haskell\
$python\
[](fg:green bg:sapphire)\
$conda\
[](fg:sapphire bg:lavender)\
$time\
[ ](fg:lavender)\
$cmd_duration\
$line_break\
$character"""
palette = 'catppuccin_mocha'
[os]
disabled = false
style = "bg:red fg:crust"
[os.symbols]
Windows = ""
Ubuntu = "󰕈"
SUSE = ""
Raspbian = "󰐿"
Mint = "󰣭"
Macos = "󰀵"
Manjaro = ""
Linux = "󰌽"
Gentoo = "󰣨"
Fedora = "󰣛"
Alpine = ""
Amazon = ""
Android = ""
AOSC = ""
Arch = "󰣇"
Artix = "󰣇"
CentOS = ""
Debian = "󰣚"
Redhat = "󱄛"
RedHatEnterprise = "󱄛"
[username]
show_always = true
style_user = "bg:red fg:crust"
style_root = "bg:red fg:crust"
format = '[ $user]($style)'
[directory]
style = "bg:peach fg:crust"
format = "[ $path ]($style)"
truncation_length = 3
truncation_symbol = "…/"
[directory.substitutions]
"Documents" = "󰈙 "
"Downloads" = " "
"Music" = "󰝚 "
"Pictures" = " "
"Developer" = "󰲋 "
[git_branch]
symbol = ""
style = "bg:yellow"
format = '[[ $symbol $branch ](fg:crust bg:yellow)]($style)'
[git_status]
style = "bg:yellow"
format = '[[($all_status$ahead_behind )](fg:crust bg:yellow)]($style)'
[nodejs]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[bun]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[c]
symbol = " "
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[rust]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[golang]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[php]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[java]
symbol = " "
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[kotlin]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[haskell]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
[python]
symbol = ""
style = "bg:green"
format = '[[ $symbol( $version)(\(#$virtualenv\)) ](fg:crust bg:green)]($style)'
[docker_context]
symbol = ""
style = "bg:sapphire"
format = '[[ $symbol( $context) ](fg:crust bg:sapphire)]($style)'
[conda]
symbol = " "
style = "fg:crust bg:sapphire"
format = '[$symbol$environment ]($style)'
ignore_base = false
[time]
disabled = false
time_format = "%R"
style = "bg:lavender"
format = '[[ $time ](fg:crust bg:lavender)]($style)'
[line_break]
disabled = false
[character]
disabled = false
success_symbol = '[](bold fg:green)'
error_symbol = '[](bold fg:red)'
vimcmd_symbol = '[](bold fg:green)'
vimcmd_replace_one_symbol = '[](bold fg:lavender)'
vimcmd_replace_symbol = '[](bold fg:lavender)'
vimcmd_visual_symbol = '[](bold fg:yellow)'
[cmd_duration]
show_milliseconds = true
format = " in $duration "
style = "bg:lavender"
disabled = false
show_notifications = true
min_time_to_notify = 45000
[palettes.catppuccin_mocha]
rosewater = "#f5e0dc"
flamingo = "#f2cdcd"
pink = "#f5c2e7"
mauve = "#cba6f7"
red = "#f38ba8"
maroon = "#eba0ac"
peach = "#fab387"
yellow = "#f9e2af"
green = "#a6e3a1"
teal = "#94e2d5"
sky = "#89dceb"
sapphire = "#74c7ec"
blue = "#89b4fa"
lavender = "#b4befe"
text = "#cdd6f4"
subtext1 = "#bac2de"
subtext0 = "#a6adc8"
overlay2 = "#9399b2"
overlay1 = "#7f849c"
overlay0 = "#6c7086"
surface2 = "#585b70"
surface1 = "#45475a"
surface0 = "#313244"
base = "#1e1e2e"
mantle = "#181825"
crust = "#11111b"
[palettes.catppuccin_frappe]
rosewater = "#f2d5cf"
flamingo = "#eebebe"
pink = "#f4b8e4"
mauve = "#ca9ee6"
red = "#e78284"
maroon = "#ea999c"
peach = "#ef9f76"
yellow = "#e5c890"
green = "#a6d189"
teal = "#81c8be"
sky = "#99d1db"
sapphire = "#85c1dc"
blue = "#8caaee"
lavender = "#babbf1"
text = "#c6d0f5"
subtext1 = "#b5bfe2"
subtext0 = "#a5adce"
overlay2 = "#949cbb"
overlay1 = "#838ba7"
overlay0 = "#737994"
surface2 = "#626880"
surface1 = "#51576d"
surface0 = "#414559"
base = "#303446"
mantle = "#292c3c"
crust = "#232634"
[palettes.catppuccin_latte]
rosewater = "#dc8a78"
flamingo = "#dd7878"
pink = "#ea76cb"
mauve = "#8839ef"
red = "#d20f39"
maroon = "#e64553"
peach = "#fe640b"
yellow = "#df8e1d"
green = "#40a02b"
teal = "#179299"
sky = "#04a5e5"
sapphire = "#209fb5"
blue = "#1e66f5"
lavender = "#7287fd"
text = "#4c4f69"
subtext1 = "#5c5f77"
subtext0 = "#6c6f85"
overlay2 = "#7c7f93"
overlay1 = "#8c8fa1"
overlay0 = "#9ca0b0"
surface2 = "#acb0be"
surface1 = "#bcc0cc"
surface0 = "#ccd0da"
base = "#eff1f5"
mantle = "#e6e9ef"
crust = "#dce0e8"
[palettes.catppuccin_macchiato]
rosewater = "#f4dbd6"
flamingo = "#f0c6c6"
pink = "#f5bde6"
mauve = "#c6a0f6"
red = "#ed8796"
maroon = "#ee99a0"
peach = "#f5a97f"
yellow = "#eed49f"
green = "#a6da95"
teal = "#8bd5ca"
sky = "#91d7e3"
sapphire = "#7dc4e4"
blue = "#8aadf4"
lavender = "#b7bdf8"
text = "#cad3f5"
subtext1 = "#b8c0e0"
subtext0 = "#a5adcb"
overlay2 = "#9399b7"
overlay1 = "#8087a2"
overlay0 = "#6e738d"
surface2 = "#5b6078"
surface1 = "#494d64"
surface0 = "#363a4f"
base = "#24273a"
mantle = "#1e2030"
crust = "#181926"
```
#### 切换主题
修改 `palette` 字段即可切换主题:
```toml
# 可选值catppuccin_mocha默认、catppuccin_frappe、catppuccin_latte、catppuccin_macchiato
palette = 'catppuccin_mocha'
```
#### 验证配置
```powershell
# 检查 Starship 版本
starship --version
# 测试配置是否正确
starship config
```
### 完整 Profile 配置
#### PowerShell 7+ Profile
将以下内容完整粘贴到 `$PROFILE` 文件中:
```powershell
# ════════════════════════════════════════════════════════════
# PowerShell 7+ Profile
# 功能:动态窗口标题 + 智能自动补全 + Starship 集成
# ════════════════════════════════════════════════════════════
# ── 模块导入 ─────────────────────────────────────────────────
Import-Module PSReadLine
Import-Module posh-git -ErrorAction SilentlyContinue
Import-Module PSFzf -ErrorAction SilentlyContinue
# ── PSReadLine 配置 ──────────────────────────────────────────
# PS7+ 支持 HistoryAndPlugin结合历史和插件两种来源预测
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
# PS7+ 支持 ListView下拉候选列表比 InlineView 更直观)
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadLineOption -MaximumHistoryCount 10000
Set-PSReadLineOption -Colors @{
Command = 'Cyan'
Parameter = 'DarkCyan'
String = 'Yellow'
Operator = 'Magenta'
Variable = 'Green'
Comment = 'DarkGray'
InlinePrediction = 'DarkGray'
ListPrediction = 'DarkCyan'
}
# ── 快捷键绑定 ───────────────────────────────────────────────
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key Shift+Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key Ctrl+Spacebar -Function PossibleCompletions
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineKeyHandler -Key Ctrl+r -Function ReverseSearchHistory
# F2 可在 InlineView 和 ListView 之间实时切换PS7+ 专属)
Set-PSReadLineKeyHandler -Key F2 -Function SwitchPredictionView
# ── PSFzf 配置 ───────────────────────────────────────────────
if (Get-Module PSFzf -ErrorAction SilentlyContinue) {
Set-PSFzfOption -PSReadLineChordProvider 'Ctrl+t'
Set-PSFzfOption -PSReadLineChordReverseHistory 'Ctrl+r'
}
# ── WinGet 补全 ──────────────────────────────────────────────
if (Get-Command winget -ErrorAction SilentlyContinue) {
Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
# PS7+ 推荐显式设置编码,避免中文路径乱码
[Console]::InputEncoding = [System.Text.Utf8Encoding]::new()
[Console]::OutputEncoding = [System.Text.Utf8Encoding]::new()
$word = $wordToComplete.Replace('"', '""')
$ast = $commandAst.ToString().Replace('"', '""')
winget complete --word="$word" --commandline "$ast" --position $cursorPosition |
ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
}
# ── 动态窗口标题Starship 钩子)────────────────────────────
# Starship 会在每次渲染 Prompt 前自动调用此函数
function Invoke-Starship-PreCommand {
$dirName = Split-Path -Leaf $PWD.Path
$branch = ""
if (Test-Path ".git" -PathType Container) {
try {
$b = git branch --show-current 2>$null
if ($b) { $branch = " [$b]" }
} catch {}
}
$isAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)
$adminTag = if ($isAdmin) { " ⚡ADMIN" } else { "" }
$host.UI.RawUI.WindowTitle = "PS · $dirName$branch$adminTag"
}
# ── PowerToys CommandNotFound ────────────────────────────────
Import-Module -Name Microsoft.WinGet.CommandNotFound
#f45873b3-b655-43a6-b217-97c00aa0db58
# ── Starship 初始化(必须放最后)────────────────────────────
Invoke-Expression (&starship init powershell)
```
#### PowerShell 5.1 Profile
```powershell
# ════════════════════════════════════════════════════════════
# PowerShell 5.1 Profile
# 功能:动态窗口标题 + 智能自动补全 + Starship 集成
# ════════════════════════════════════════════════════════════
# ── 模块导入 ─────────────────────────────────────────────────
Import-Module PSReadLine
Import-Module posh-git -ErrorAction SilentlyContinue
Import-Module PSFzf -ErrorAction SilentlyContinue
# ── PSReadLine 配置 ──────────────────────────────────────────
# PS5.1 仅支持 History不支持 HistoryAndPlugin
Set-PSReadLineOption -PredictionSource History
# PS5.1 仅支持 InlineView不支持 ListView
Set-PSReadLineOption -PredictionViewStyle InlineView
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadLineOption -MaximumHistoryCount 10000
Set-PSReadLineOption -Colors @{
Command = 'Cyan'
Parameter = 'DarkCyan'
String = 'Yellow'
Operator = 'Magenta'
Variable = 'Green'
Comment = 'DarkGray'
InlinePrediction = 'DarkGray'
}
# ── 快捷键绑定 ───────────────────────────────────────────────
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key Shift+Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key Ctrl+Spacebar -Function PossibleCompletions
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineKeyHandler -Key Ctrl+r -Function ReverseSearchHistory
# ── PSFzf 配置 ───────────────────────────────────────────────
if (Get-Module PSFzf -ErrorAction SilentlyContinue) {
Set-PSFzfOption -PSReadLineChordProvider 'Ctrl+t'
Set-PSFzfOption -PSReadLineChordReverseHistory 'Ctrl+r'
}
# ── WinGet 补全 ──────────────────────────────────────────────
if (Get-Command winget -ErrorAction SilentlyContinue) {
Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
$word = $wordToComplete.Replace('"', '""')
$ast = $commandAst.ToString().Replace('"', '""')
winget complete --word="$word" --commandline "$ast" --position $cursorPosition |
ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
}
# ── 动态窗口标题Starship 钩子)────────────────────────────
function Invoke-Starship-PreCommand {
$dirName = Split-Path -Leaf $PWD.Path
$branch = ""
if (Test-Path ".git" -PathType Container) {
try {
$b = git branch --show-current 2>$null
if ($b) { $branch = " [$b]" }
} catch {}
}
$isAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)
$adminTag = if ($isAdmin) { " ⚡ADMIN" } else { "" }
$host.UI.RawUI.WindowTitle = "PS · $dirName$branch$adminTag"
}
# ── Starship 初始化(必须放最后)────────────────────────────
Invoke-Expression (&starship init powershell)
```
### 功能说明
#### 动态窗口标题
标题由以下三部分拼接而成:
```
PS · <当前目录名> [<Git分支>] <管理员标识>
```
**示例效果:**
| 场景 | 窗口标题 |
|------|----------|
| 普通目录 | `PS · Downloads` |
| Git 仓库 | `PS · my-project [main]` |
| 管理员身份 | `PS · System32 ⚡ADMIN` |
| 管理员 + Git | `PS · infra [feat/deploy] ⚡ADMIN` |
**实现原理:** 利用 Starship 预留的 `Invoke-Starship-PreCommand` 钩子函数,在每次渲染 Prompt 之前执行,与 Starship 完全兼容,无冲突。
#### 自动补全配置
配置分为四个层次,可按需选择叠加:
| 层次 | 功能 | 说明 |
|------|------|------|
| Layer 1 | PSReadLine 历史预测 | 输入部分命令后,灰色文字实时预测完整命令,按 `→` 接受 |
| Layer 2 | Tab 菜单补全 | 按 `Tab` 弹出候选菜单,上下键选择,`Enter` 确认 |
| Layer 3 | posh-git 补全 | 为 `git` 命令提供子命令、分支名、远程名等补全 |
| Layer 4 | PSFzf 模糊搜索 | `Ctrl+R` 调出交互式历史命令搜索窗口,支持模糊匹配 |
### 快捷键速查
| 快捷键 | 功能 | PS5.1 | PS7+ |
|--------|------|-------|------|
| `→` | 接受行内预测 | ✅ | ✅ |
| `Tab` | 菜单补全,循环切换候选 | ✅ | ✅ |
| `Shift+Tab` | 反向切换候选 | ✅ | ✅ |
| `Ctrl+Space` | 显示所有候选项 | ✅ | ✅ |
| `↑ / ↓` | 按前缀过滤历史记录 | ✅ | ✅ |
| `Ctrl+R` | fzf 模糊历史搜索 | ✅ | ✅ |
| `Ctrl+T` | fzf 模糊文件查找 | ✅ | ✅ |
| `F2` | 切换 InlineView / ListView | ❌ | ✅ |
### 版本功能对照
| 功能 | PS5.1 | PS7+ | 说明 |
|------|-------|------|------|
| `PredictionSource History` | ✅ | ✅ | 基于历史命令预测 |
| `PredictionSource HistoryAndPlugin` | ❌ | ✅ | 额外加入插件预测源 |
| `PredictionViewStyle InlineView` | ✅ | ✅ | 行内灰字预测 |
| `PredictionViewStyle ListView` | ❌ | ✅ | 下拉候选列表 |
| `F2` 切换预测视图 | ❌ | ✅ | 实时切换两种视图 |
| PSReadLine 最高版本 | 2.3.x | 最新版 | 安装时需注意 |
| posh-git | ✅ | ✅ | 版本一致 |
| PSFzf | ✅ | ✅ | 版本一致 |
| WinGet 补全 | ✅ | ✅ | 编码处理略有差异 |
| Starship 钩子 | ✅ | ✅ | 函数名一致 |
| 动态窗口标题 | ✅ | ✅ | 实现方式一致 |
> PS5.1 缺少的 `ListView``HistoryAndPlugin` 可通过 PSFzf 的 `Ctrl+R` 模糊搜索弥补,日常体验差距不大。
### 常见问题
#### 执行 `. $PROFILE` 报执行策略错误
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
#### 模块安装报 NuGet 错误
```powershell
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
```
#### PSReadLine 安装后不生效
PS5.1 系统自带一个旧版 PSReadLine新版安装在用户目录下需确认加载的是新版
```powershell
Get-Module PSReadLine | Select-Object Name, Version, Path
# Path 应包含 CurrentUser 路径,而非 System32
```
如果仍加载旧版,在 Profile 最顶部显式指定:
```powershell
Remove-Module PSReadLine -ErrorAction SilentlyContinue
Import-Module PSReadLine -RequiredVersion 2.3.4
```
#### fzf / PSFzf 的 Ctrl+R 不弹出窗口
确认 fzf 本体已安装且在 PATH 中:
```powershell
fzf --version
```
如果命令不存在,重新安装并重启终端:
```powershell
winget install junegunn.fzf
```
#### 窗口标题不更新
确认 `Invoke-Starship-PreCommand` 函数定义在 `Invoke-Expression (&starship init powershell)` **之前**,因为 Starship init 会注册对该钩子的调用,函数本身需要提前存在。
#### posh-git 导致启动变慢
posh-git 在大型仓库中可能扫描较慢,可设置跳过未跟踪文件统计:
```powershell
$GitPromptSettings.EnableFileStatus = $false
```
## 编辑oh-my-posh配置文件 ## 编辑oh-my-posh配置文件
打开**PowerShell**终端,执行以下命令编辑配置文件 `code $PROFILE` 打开**PowerShell**终端,执行以下命令编辑配置文件 `code $PROFILE`