← Windows与WSL的终端美化

Windows与WSL的终端美化(二)——WezTerm配置

上一篇把 WSL 这层地基先垫平了,这一篇终于可以开始收拾“门面”了。

我对 Windows 侧终端的要求其实很简单,第一眼别丑,第二眼别乱,第三眼别脆。好看只是基础,真正决定日常体验的,是它能不能稳稳接住 Windows、WSL、中文、Nerd Font 图标、emoji,还有一堆我会天天按到的快捷键。折腾一圈以后,我最后把入口定在了 WezTerm。

这篇不是只讲概念,我会把项目文档 D:\Bed\30-projects\terminal-beautify\02-WezTerm-setup.md 和我正在用的实际配置 C:\Users\12907\.wezterm.lua 一起拆开讲。完整配置文件一共有 435 行,这里不把 435 行原样全贴出来,但会按模块把关键结构、配置逻辑、快捷键和排坑点全部讲清楚,代码块也都会保持可直接使用。

为什么我最后选 WezTerm

一开始最容易拿来比较的,其实就是 Windows TerminalWezTermAlacritty

如果你只是想开个 shell,三者都能干活。可一旦你想把终端当成长期入口,要求统一主题、中文回退、WSL 入口、状态栏、标题栏、毛玻璃、快捷键逻辑都能自己控制,差距就会很快拉开。

对比项 Windows Terminal WezTerm Alacritty
GPU 渲染 DirectX WebGPU / OpenGL OpenGL
配置语言 JSON Lua,可编程 TOML
字体 fallback chain 有,但可玩性有限 完整支持,适合中英混排 较弱,不适合复杂回退
WSL 接入 通过 profile 配置 内置 wsl_domains 需手动配启动命令
动态逻辑 较少 很强,可以写函数和事件 较少
Win11 Mica 毛玻璃 支持 支持 不支持
Tab 标题 / 状态栏深度定制 一般 很强 较少
适合我这套工作流的原因 开箱即用 灵活、稳、能写逻辑 快,但不够细

我最后选 WezTerm,核心原因其实就三条:

  1. Lua 配置是真的够灵活。不是“多几个开关”那种灵活,而是可以自己写函数、处理事件、切主题、改标题、改状态栏、改窗口行为。
  2. 字体 fallback chain 更完整。Windows 里最容易出问题的,就是英文、中文、Nerd Font 图标、emoji 混在一起以后显示乱套。WezTerm 在这块明显更顺手。
  3. WSL 入口可以做得既方便又稳定。我可以声明 WSL 域,但不把它设成默认启动,这样 PowerShell 先稳稳起来,WSL 需要时一键再进。

简单说,Windows Terminal 更像“系统自带的好工具”,Alacritty 更像“很快的轻量跑车”,WezTerm 则更像“能按自己习惯慢慢打磨的工作台”。我最后要的是第三种。

安装 WezTerm

安装本体很直接,我建议优先用包管理器。装完以后先手动启动一次,确认程序本身能正常打开,再去写配置文件。

用 winget 安装

winget install wez.wezterm

用 scoop 安装

scoop install wezterm

装好以后可以顺手看一下版本:

wezterm -V

如果命令能正常返回版本号,说明可执行文件已经进 PATH 了,后面排错会轻松很多。

字体先装好,不然后面全是方块

WezTerm 的体验,有一半其实是字体体验。你要是只装了一个普通英文字体,中文、图标、emoji 一混,问题就会立刻冒出来。

项目文档里的方案是 JetBrainsMono Nerd Font + 中文回退字体。我当前机器的实际配置链则是:

  • 主字体:JetBrains Mono
  • 英文补位:Cascadia Mono
  • 中文回退:Microsoft YaHei UI
  • emoji 回退:Noto Color Emoji

这里有个细节要先说清楚:你安装的字体包名,和 WezTerm 里要写的 family 名,不一定一模一样。

比如你通过 Nerd Fonts 安装的是 JetBrainsMono Nerd Font,可你系统里真正显示给 WezTerm 的 family 名,可能是 JetBrains MonoJetBrainsMono Nerd Font,也可能是 JetBrainsMono Nerd Font Mono。所以最稳的做法,是先装字体,再用 WezTerm 实际识别到的 family 名写配置。

安装 JetBrainsMono Nerd Font

可以去 Nerd Fonts 官网下载,也可以直接用 scoop:

scoop bucket add nerd-fonts
scoop install JetBrainsMono-NF

如果你更喜欢手动下载,项目文档里的来源是:

https://www.nerdfonts.com/font-downloads

中文回退字体怎么选

这套配置里我实际用的是 Microsoft YaHei UI,它的好处很直接,Windows 自带,开箱就有,中文显示也稳。

项目文档里还提到过 Sarasa Mono SC 作为可选方案。如果你特别想要更接近等宽的中文观感,可以试它;但按我现在这份真实配置来说,正在使用的中文 fallback 仍然是 Microsoft YaHei UI

emoji 则交给 Noto Color Emoji 收尾。

装完字体以后,先做一次检查

wezterm ls-fonts --text "Hello 中文 󰆍 😀"

这条命令很实用。它会把当前能匹配到的字体列出来,你可以直接看中文、图标、emoji 是不是都有人接住。

装完字体以后,建议把 WezTerm 完全退出,再重新打开一次。字体缓存不刷新的时候,很多人会误以为配置没生效。

配置文件放在哪里

Windows 下最常见的位置就是:

C:\Users\12907\.wezterm.lua

如果你想直接编辑:

notepad $env:USERPROFILE\.wezterm.lua

我当前实际使用的完整配置就在这个路径里。文件不短,但结构是清楚的,拆开以后大致是这样:

.wezterm.lua
├─ 01. require + config_builder + strict_mode
├─ 02. Catppuccin Mocha 色板定义
├─ 03. Mocha Glass / Mocha Contrast 双模式
├─ 04. 默认 Shell 与 WSL 域声明
├─ 05. 字体 fallback chain
├─ 06. Window 配置
├─ 07. Tab Bar 配色
├─ 08. Cursor 与性能参数
├─ 09. Helper Functions
│  ├─ basename
│  ├─ cwd_from_uri
│  ├─ normalize_process_name
│  ├─ clamp
│  ├─ round_opacity
│  ├─ effective_window_mode
│  ├─ set_glass_backdrop_for_opacity
│  ├─ adjust_opacity
│  └─ apply_toggle_theme_mode
├─ 10. format-tab-title 事件
├─ 11. update-right-status 事件
└─ 12. keys,自定义快捷键

也就是说,这份配置不是只改几个外观参数,而是把“配色、窗口、字体、标题栏、状态栏、快捷键、启动策略”整个串到了一起。

下面按模块拆开讲。

先把配置文件骨架搭起来

我很喜欢在 WezTerm 里开 strict_mode。原因很简单,Lua 配置一旦写错字段名,很多错误肉眼不一定马上看出来。严格模式会让问题早点暴露,不用靠猜。

local wezterm = require 'wezterm'
local config = wezterm.config_builder()

config:set_strict_mode(true)

这三行虽然简单,但很值得保留。

Catppuccin Mocha 色板定义

这套终端环境从头到尾都统一在 Catppuccin Mocha 上,所以颜色我没有东拼西凑,而是先把整套 Mocha 色板显式写出来,后面 Tab Bar、状态栏、标题栏、Glass / Contrast 模式都统一引用它。

local mocha = {
  base      = '#1e1e2e',
  mantle    = '#181825',
  crust     = '#11111b',
  surface0  = '#313244',
  surface1  = '#45475a',
  surface2  = '#585b70',
  overlay0  = '#6c7086',
  text      = '#cdd6f4',
  subtext1  = '#bac2de',
  subtext0  = '#a6adc8',
  blue      = '#89b4fa',
  lavender  = '#b4befe',
  sapphire  = '#74c7ec',
  sky       = '#89dceb',
  teal      = '#94e2d5',
  green     = '#a6e3a1',
  yellow    = '#f9e2af',
  peach     = '#fab387',
  maroon    = '#eba0ac',
  red       = '#f38ba8',
  mauve     = '#cba6f7',
  pink      = '#f5c2e7',
  flamingo  = '#f2cdcd',
  rosewater = '#f5e0dc',
}

把颜色单独抽成 mocha 这张表以后,后面你想改 active tab、cursor、status cell、分隔符颜色,都不需要再去翻十几处十六进制值。

Glass / Contrast 双模式配置

这部分是整份 WezTerm 配置里我最喜欢的地方。

我平时默认用 Mocha Glass,背景半透明,配合 Windows 11 的 Mica 效果,窗口会有一点贴着桌面的层次感。白天环境光强,或者背景太杂的时候,我会切到 Mocha Contrast,把背景直接打实,光标和选区也一起增强。

先看主题本身的定义:

local scheme = wezterm.color.get_builtin_schemes()['Catppuccin Mocha']
scheme.background = mocha.base
scheme.selection_bg = mocha.surface1
scheme.cursor_bg = mocha.rosewater
scheme.cursor_border = mocha.rosewater
scheme.cursor_fg = mocha.base

local contrast_scheme = {}
for key, value in pairs(scheme) do
  contrast_scheme[key] = value
end
contrast_scheme.background = mocha.crust
contrast_scheme.selection_bg = mocha.surface2
contrast_scheme.cursor_bg = mocha.yellow
contrast_scheme.cursor_border = mocha.yellow
contrast_scheme.cursor_fg = mocha.crust

config.color_schemes = {
  ['Mocha Glass'] = scheme,
  ['Mocha Contrast'] = contrast_scheme,
}
config.color_scheme = 'Mocha Glass'

这段逻辑有两个重点:

  1. 先从 WezTerm 内置的 Catppuccin Mocha 起步。
  2. 再派生出两个变体,一个偏玻璃感,一个偏高对比。

接下来是运行时切换主题和透明度时会用到的辅助函数,也是这份配置真正“可用”的关键:

local default_glass_opacity = 0.92
local min_opacity = 0.70
local max_opacity = 1.00
local opacity_step = 0.01

local function clamp(value, lower, upper)
  if value < lower then
    return lower
  end
  if value > upper then
    return upper
  end
  return value
end

local function round_opacity(value)
  return math.floor(value * 100 + 0.5) / 100
end

local function effective_window_mode(window)
  local overrides = window and window:get_config_overrides() or {}
  local color_scheme = overrides.color_scheme or config.color_scheme
  local opacity = overrides.window_background_opacity or config.window_background_opacity
  local backdrop = overrides.win32_system_backdrop or config.win32_system_backdrop

  return {
    color_scheme = color_scheme,
    opacity = opacity,
    backdrop = backdrop,
  }
end

local function set_glass_backdrop_for_opacity(overrides, color_scheme, opacity)
  if color_scheme == 'Mocha Glass' then
    overrides.win32_system_backdrop = opacity < 1.0 and 'Mica' or 'Disable'
  else
    overrides.win32_system_backdrop = 'Disable'
  end
end

local function adjust_opacity(window, delta)
  local overrides = window:get_config_overrides() or {}
  local mode = effective_window_mode(window)
  local next_opacity = round_opacity(clamp(mode.opacity + delta, min_opacity, max_opacity))

  overrides.window_background_opacity = next_opacity
  set_glass_backdrop_for_opacity(overrides, mode.color_scheme, next_opacity)

  window:set_config_overrides(overrides)
end

local function apply_toggle_theme_mode(window)
  local overrides = window:get_config_overrides() or {}
  local mode = effective_window_mode(window)

  if mode.color_scheme == 'Mocha Glass' then
    overrides.color_scheme = 'Mocha Contrast'
    overrides.window_background_opacity = 1.0
    overrides.win32_system_backdrop = 'Disable'
  else
    overrides.color_scheme = 'Mocha Glass'
    overrides.window_background_opacity = default_glass_opacity
    set_glass_backdrop_for_opacity(overrides, overrides.color_scheme, overrides.window_background_opacity)
  end

  window:set_config_overrides(overrides)
end

这块实际行为也很清楚:

  • Mocha Glass 默认透明度是 0.92
  • 透明度可调范围是 0.701.00
  • 每次调节步进是 0.01
  • 只要背景变成 1.00,Mica 就会被关掉
  • 切到 Mocha Contrast 时,会强制 opacity = 1.0
  • 再切回 Mocha Glass 时,会回到默认 0.92

也就是说,这不是简单的“换个颜色名”,而是把颜色、透明度、Mica 行为一起切了。

默认 Shell 为什么是 PowerShell,而不是直接进 WSL

很多人第一次配 WezTerm,最容易写出下面这种配置:

config.default_domain = 'WSL:Ubuntu'

看上去很省事,打开终端就直达 Ubuntu。问题是,这种写法一旦遇到 WSL 状态不对、系统刚开机、某次发行版异常,WezTerm 本身也可能跟着一起闪退。

我现在实际用的方案更稳:默认先进 PowerShell,只把 WSL 声明成一个可选域,按需进入。

config.default_prog = { 'pwsh.exe', '-NoLogo' }

config.wsl_domains = {
  {
    name = 'WSL:Ubuntu',
    distribution = 'Ubuntu',
  },
}

-- 注意:不要默认写成下面这样
-- config.default_domain = 'WSL:Ubuntu'

我会这样配,原因有三点:

  1. PowerShell 是更稳的 Windows 侧入口。先让终端本体起来,再决定要不要进 WSL,排错简单很多。
  2. Windows 和 WSL 的边界更清楚。有些命令本来就该在 Windows 侧跑,比如包管理器、某些系统排障命令。
  3. WSL 仍然是一键可达。我在快捷键里专门绑了 Ctrl+Shift+U,直接新开一个 Ubuntu tab。

我不是不想自动,而是不想把整个终端入口绑在一个可能偶尔掉链子的默认域上。

字体 fallback chain,为什么这么排

真实配置如下:

config.font = wezterm.font_with_fallback({
  { family = 'JetBrains Mono', weight = 'Medium' },
  { family = 'Cascadia Mono', weight = 'Regular' },
  { family = 'Microsoft YaHei UI', scale = 1.15 },
  'Noto Color Emoji',
})
config.font_size = 12.5
config.line_height = 1.10
config.cell_width = 1.0

这条链每一层都有分工:

  • JetBrains Mono 负责主力英文代码显示
  • Cascadia Mono 负责补一层英文字形和符号兼容
  • Microsoft YaHei UI 负责把中文稳稳接住,同时通过 scale = 1.15 让观感更接近前面的英文字体
  • Noto Color Emoji 收尾,避免 emoji 直接变问号或方块

再强调一次,项目方案里安装的是 JetBrainsMono Nerd Font,但你最终在 family 里写什么,要以 WezTerm 实际识别到的名称为准。

如果你本机识别到的是 JetBrainsMono Nerd Font,就把第一行改成下面这样:

config.font = wezterm.font_with_fallback({
  { family = 'JetBrainsMono Nerd Font', weight = 'Medium' },
  { family = 'Cascadia Mono', weight = 'Regular' },
  { family = 'Microsoft YaHei UI', scale = 1.15 },
  'Noto Color Emoji',
})

你会发现,这里我没有追求“所有字符都由一个字体包解决”,而是老老实实交给 fallback chain 分层处理。这样更稳。

Window 配置,重点是 Mica 毛玻璃和尺寸手感

窗口模块本身不复杂,但它直接决定了终端是像“默认黑框”,还是像一个认真打磨过的桌面部件。

config.initial_cols = 120
config.initial_rows = 32

config.window_padding = {
  left = 12,
  right = 12,
  top = 8,
  bottom = 6,
}

config.window_background_opacity = 0.92
config.win32_system_backdrop = 'Mica'
config.window_decorations = 'RESIZE'
config.adjust_window_size_when_changing_font_size = false

几个关键点可以单独看:

  • initial_cols = 120initial_rows = 32,是一个很适合日常开发的默认窗口尺寸
  • window_padding 给终端内容留了呼吸感,不会一贴边就显得拥挤
  • window_background_opacity = 0.92 配合 Mica,就是我默认的玻璃模式手感
  • window_decorations = 'RESIZE' 保留可调整大小的边框,但不保留传统标题栏那种厚重感
  • adjust_window_size_when_changing_font_size = false 能避免调字号时整个窗口跟着乱跳

真正需要记住的一条是:这份配置只在 Glass 模式下保留 Mica,Contrast 模式会把它关掉。 这不是 bug,是故意的。

Tab Bar 配置,配色和信息量都要刚好

WezTerm 本身的 Tab Bar 已经够用,但既然整套环境都在走 Catppuccin Mocha,我就顺手把它也统一了。当前配置的思路是:

  • 不用 fancy tab bar,自己掌控配色
  • tab bar 放到底部
  • 不隐藏单 tab 状态,这样整体结构更稳定
  • 去掉 new tab 按钮,让视觉更干净

基础样式如下:

config.use_fancy_tab_bar = false
config.hide_tab_bar_if_only_one_tab = false
config.show_new_tab_button_in_tab_bar = false
config.tab_bar_at_bottom = true

config.colors = {
  tab_bar = {
    background = mocha.mantle,
    active_tab = {
      bg_color = mocha.blue,
      fg_color = mocha.base,
      intensity = 'Bold',
    },
    inactive_tab = {
      bg_color = mocha.surface0,
      fg_color = mocha.subtext0,
    },
    inactive_tab_hover = {
      bg_color = mocha.surface1,
      fg_color = mocha.text,
      italic = false,
    },
    new_tab = {
      bg_color = mocha.mantle,
      fg_color = mocha.blue,
    },
    new_tab_hover = {
      bg_color = mocha.surface1,
      fg_color = mocha.text,
      italic = false,
    },
  },
  scrollbar_thumb = mocha.surface1,
  split = mocha.surface2,
}

这只是底色。真正让 tab 变得好用的,是标题格式化逻辑。

当前配置里,tab title 会自动显示:

序号 + 当前目录名 + 前台进程名

比如 1 project nvim 这种结构,一眼就知道每个 tab 在干什么。相关辅助函数和事件回调如下:

local function basename(path)
  if not path or path == '' then
    return ''
  end

  local name = string.gsub(path, '(.*[/\\])(.*)', '%2')
  if name == '' then
    return path
  end

  return name
end

local function cwd_from_uri(cwd_uri)
  if not cwd_uri then
    return ''
  end

  if type(cwd_uri) == 'userdata' then
    return cwd_uri.file_path or ''
  end

  local uri = tostring(cwd_uri)
  if uri:sub(1, 8) == 'file:///' then
    uri = uri:sub(9)
  elseif uri:sub(1, 7) == 'file://' then
    uri = uri:sub(8)
  end

  uri = uri:gsub('%%(%x%x)', function(hex)
    return string.char(tonumber(hex, 16))
  end)

  return uri
end

local function normalize_process_name(process_name)
  local name = basename(process_name)
  if name == '' then
    return ''
  end

  if name:lower():sub(-4) == '.exe' then
    name = name:sub(1, -5)
  end

  return name
end

local function tab_title(tab)
  local explicit_title = tab.tab_title
  if explicit_title and #explicit_title > 0 then
    return string.format('%d  %s', tab.tab_index + 1, explicit_title)
  end

  local pane = tab.active_pane
  local process_name = normalize_process_name(pane.foreground_process_name)
  local cwd = cwd_from_uri(pane.current_working_dir)
  local cwd_name = basename(cwd)
  local segments = { string.format('%d', tab.tab_index + 1) }

  if cwd_name ~= '' then
    table.insert(segments, ' ' .. cwd_name)
  end

  if process_name ~= '' then
    table.insert(segments, '󰆍 ' .. process_name)
  end

  if #segments == 1 then
    table.insert(segments, '󰆍 shell')
  end

  return table.concat(segments, '  ')
end

wezterm.on('format-tab-title', function(tab, tabs, panes, cfg, hover, max_width)
  local background = mocha.surface0
  local foreground = mocha.subtext0

  if tab.is_active then
    background = mocha.blue
    foreground = mocha.base
  elseif hover then
    background = mocha.surface1
    foreground = mocha.text
  end

  local edge_background = mocha.mantle
  local edge_foreground = background
  local title = wezterm.truncate_right(tab_title(tab), math.max(max_width - 10, 1))

  return {
    { Background = { Color = edge_background } },
    { Foreground = { Color = edge_foreground } },
    { Text = wezterm.nerdfonts.pl_right_hard_divider },
    { Background = { Color = background } },
    { Foreground = { Color = foreground } },
    { Text = ' 󰆍 ' .. title .. ' ' },
    { Background = { Color = edge_background } },
    { Foreground = { Color = edge_foreground } },
    { Text = wezterm.nerdfonts.pl_left_hard_divider },
  }
end)

这段代码解决了几个很实际的问题:

  • 当前目录只取最后一级,信息不会过长
  • 前台进程名会去掉 .exe 后缀,标题更干净
  • URI 会被解码,Windows 和 WSL 场景都能正常取目录
  • active / hover / inactive 状态配色分明,但不刺眼

Right Status 配置,右上角那一小条其实很有用

除了 tab 标题,我还在右上角放了一条状态信息。内容不花,但很实用:

  • 当前目录
  • 当前前台进程
  • 当前模式,glass 或 contrast
  • 当前透明度百分比
  • 当前时间

相关事件代码如下:

wezterm.on('update-right-status', function(window, pane)
  local cwd = cwd_from_uri(pane:get_current_working_dir())
  local cwd_name = basename(cwd)
  local process_name = normalize_process_name(pane:get_foreground_process_name() or '')
  local mode = effective_window_mode(window)

  if process_name == '' then
    process_name = 'shell'
  end

  local cells = {
    { icon = '',  text = cwd_name ~= '' and cwd_name or '~', bg = mocha.surface0 },
    { icon = '󰆍', text = process_name, bg = mocha.surface1 },
    { icon = '',  text = mode.color_scheme == 'Mocha Glass' and 'glass' or 'contrast', bg = mocha.surface2 },
    { icon = '󰖔', text = string.format('%d%%', math.floor(mode.opacity * 100 + 0.5)), bg = mocha.overlay0 },
    { icon = wezterm.nerdfonts.fa_clock_o, text = wezterm.strftime('%Y-%m-%d %H:%M'), bg = mocha.surface2 },
  }

  local elements = {}
  for index, cell in ipairs(cells) do
    table.insert(elements, { Background = { Color = cell.bg } })
    table.insert(elements, { Foreground = { Color = mocha.text } })
    table.insert(elements, { Text = ' ' .. cell.icon .. ' ' .. cell.text .. ' ' })

    if index < #cells then
      table.insert(elements, { Background = { Color = cell.bg } })
      table.insert(elements, { Foreground = { Color = cells[index + 1].bg } })
      table.insert(elements, { Text = wezterm.nerdfonts.pl_left_hard_divider })
    end
  end

  window:set_right_status(wezterm.format(elements))
end)

我很喜欢这个写法的一点,是它不需要很多颜色,只用 surface0surface1surface2overlay0 几层明暗,就能把信息分区做得很清楚。

Cursor 与性能参数,小设置也会影响日常手感

这部分不是视觉主角,但天天都能感觉到:

config.animation_fps = 60
config.max_fps = 120
config.cursor_blink_rate = 650
config.default_cursor_style = 'BlinkingBar'
config.audible_bell = 'Disabled'

这里我的取舍也很明确:

  • animation_fps = 60,日常动画够顺
  • max_fps = 120,给高刷屏一点发挥空间
  • BlinkingBar 比方块光标更轻一点
  • audible_bell = 'Disabled',直接把烦人的响铃关掉

都是小地方,但终端这种天天盯着看的东西,正是小地方在累积体验。

所有自定义快捷键说明

当前 C:\Users\12907\.wezterm.lua 里一共定义了下面这些自定义快捷键:

config.keys = {
  {
    key = 'F9',
    mods = 'CTRL|SHIFT',
    action = wezterm.action_callback(function(window, pane)
      adjust_opacity(window, -opacity_step)
    end),
  },
  {
    key = 'F10',
    mods = 'CTRL|SHIFT',
    action = wezterm.action_callback(function(window, pane)
      adjust_opacity(window, opacity_step)
    end),
  },
  {
    key = 'F11',
    mods = 'CTRL|SHIFT',
    action = wezterm.action_callback(function(window, pane)
      apply_toggle_theme_mode(window)
    end),
  },
  {
    key = 'u',
    mods = 'CTRL|SHIFT',
    action = wezterm.action.SpawnCommandInNewTab {
      domain = { DomainName = 'WSL:Ubuntu' },
    },
  },
  {
    key = 'w',
    mods = 'CTRL|SHIFT|ALT',
    action = wezterm.action.CloseCurrentPane { confirm = true },
  },
  {
    key = 'F11',
    action = wezterm.action.ToggleFullScreen,
  },
  {
    key = 'p',
    mods = 'CTRL|SHIFT',
    action = wezterm.action.ActivateCommandPalette,
  },
}

把它翻成人话,就是下面这张表:

快捷键 作用 实际行为
Ctrl+Shift+F9 降低透明度 每次减 0.01,最低到 0.70
Ctrl+Shift+F10 增加透明度 每次加 0.01,最高到 1.00
Ctrl+Shift+F11 切换 Glass / Contrast Glass -> Contrast 会变成全不透明,Contrast -> Glass 会回到 0.92
Ctrl+Shift+U 新开 Ubuntu tab 通过 WSL:Ubuntu 域进入 WSL
Ctrl+Shift+Alt+W 关闭当前 pane 只关当前 pane,不连带整个 tab
F11 全屏切换 当前窗口全屏 / 退出全屏
Ctrl+Shift+P 打开 Command Palette 用模糊搜索方式找命令和动作

这里我没有贪多。真正天天会按的,其实也就是透明度、模式切换、快速进 WSL、关闭 pane 这几组。剩下像 F11Ctrl+Shift+P,更多是把高频动作明确留出来,省得再去记菜单位置。

WezTerm 通用快捷键速查表

除了上面这些自定义绑定,日常最常用的一组通用快捷键也可以顺手记一下。具体版本之间可能会有细微差异,最稳的做法始终是按 Ctrl+Shift+P 打开 Command Palette 查当前可用命令。

Tab 管理

快捷键 功能
Ctrl+Shift+T 新建 tab
Ctrl+Shift+W 关闭当前 tab
Ctrl+Tab 切换到下一个 tab
Ctrl+Shift+Tab 切换到上一个 tab
Ctrl+Shift+1Ctrl+Shift+9 跳转到第 N 个 tab

Pane 分屏

快捷键 功能
Ctrl+Shift+Alt+" 水平分屏,上下布局
Ctrl+Shift+Alt+% 垂直分屏,左右布局
Ctrl+Shift+Arrow 在 pane 之间切换焦点
Ctrl+Shift+Z 放大或还原当前 pane
Ctrl+Shift+Alt+W 关闭当前 pane

复制、粘贴与选择

快捷键 功能
Ctrl+Shift+C 复制选中文本
Ctrl+Shift+V 从剪贴板粘贴
Ctrl+Shift+X 进入 Copy Mode
Ctrl+Shift+Space Quick Select,快速选中 URL、hash 等内容

字号与窗口

快捷键 功能
Ctrl+= 增大字号
Ctrl+- 减小字号
Ctrl+0 重置字号
F11 全屏切换
Ctrl+Shift+L 打开 Debug Overlay
Ctrl+Shift+P 打开 Command Palette

搜索与滚动

快捷键 功能
Ctrl+Shift+F 搜索终端输出
Shift+PageUp 向上翻页
Shift+PageDown 向下翻页

如果你记不住,也没关系。命令面板本身就是最好的备忘录。

常见问题排查

1. 字体显示成方块,或者 Tab 标题里的图标不对

先检查三件事:

  1. JetBrainsMono Nerd Font 是否真的装上了
  2. WezTerm 配置里写的 family 名,是否和系统实际识别到的一致
  3. Microsoft YaHei UINoto Color Emoji 是否能正常接住中文和 emoji

可以直接跑:

wezterm ls-fonts --text "Hello 中文 󰆍 😀"

如果结果里没有你以为已经安装的字体,大概率就是 family 名没对上。装完字体后,也记得彻底重启 WezTerm。

2. WezTerm 启动闪退

最常见的原因,就是把下面这行设成了默认:

config.default_domain = 'WSL:Ubuntu'

只要 WSL 状态有问题,WezTerm 就可能跟着闪退。

更稳的做法,就是本文现在这套配置:

  • 默认启动 pwsh.exe
  • 只声明 wsl_domains
  • Ctrl+Shift+U 按需新开 WSL tab

如果已经闪退了,可以在 PowerShell 里直接运行:

wezterm start

这样至少能先把错误输出看到。

3. Mica 毛玻璃不生效

这类问题一般从下面几项排:

  1. 系统是不是 Windows 11 22H2 及以上
  2. WezTerm 版本是不是足够新,项目文档里给的经验线是 20230712 以上
  3. 当前是不是 Mocha Glass 模式,而不是 Mocha Contrast
  4. 当前透明度是不是小于 1.0
  5. win32_system_backdrop 有没有被切换逻辑改成 Disable

你如果刚按过 Ctrl+Shift+F11,很可能已经在 Contrast 模式里了。这种情况下不透明是正常表现,不是配置失效。

4. 透明度快捷键按了没反应

先确认你当前不是别的程序抢了快捷键。然后再看两点:

  • 透明度已经到边界了没有,最小 0.70,最大 1.00
  • 当前主题模式是什么,如果已经在 1.00Mica 被关掉,看起来会像“没有变化”

如果想快速回到默认玻璃态,直接按:

Ctrl+Shift+F11

它会把主题切回 Mocha Glass,透明度重置为 0.92

5. 中文看起来发虚,或者和英文高低不齐

这通常不是 WezTerm 的问题,而是 fallback 链还没调顺。

我当前配置里专门给 Microsoft YaHei UI 加了:

{ family = 'Microsoft YaHei UI', scale = 1.15 }

如果你换了别的中文字体,scale 往往也要跟着重新试一下。不然最容易出现的就是中文偏小、偏扁,或者和英文基线不齐。

一份当前可直接参考的配置思路

如果把前面所有内容压缩成一句话,我这份 WezTerm 配置的核心其实就是:

  • 用 PowerShell 保证入口稳定
  • wsl_domains 和快捷键保证 WSL 一键可达
  • 用 Catppuccin Mocha 做统一底色
  • 用 Glass / Contrast 双模式兼顾观感和可读性
  • 用 fallback chain 解决中英混排、图标和 emoji
  • 用标题栏、状态栏、快捷键把终端真正变成工作台

你真把这层收拾顺以后,后面的 Zellij、Zsh、Starship 才会像是在一张已经布置好的桌面上继续往下摆,而不是在一个随时可能出毛病的入口上硬堆功能。

下一篇我会继续往里走,把终端里的工作区真正搭起来,也就是 Zellij 那一层。

系列文章导航

  1. Windows与WSL的终端美化(零)——系列概览
  2. Windows与WSL的终端美化(一)——WSL安装与配置
  3. Windows与WSL的终端美化(二)——WezTerm配置(本篇)
  4. Windows与WSL的终端美化(三)——Zellij工作区管理
  5. Windows与WSL的终端美化(四)——Shell与Prompt配置
  6. Windows与WSL的终端美化(五)——CLI工具链美化
  7. Windows与WSL的终端美化(六)——Catppuccin主题统一
目录

Comments (1)

exception 2026-05-26 04:23:50
您好,请问您方便把自用的WezTerm完整配置文件分享一下吗? 感谢