← 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 (0)

No comments yet. Be the first!