my new websites homepage on mobile

I switched to WezTerm

Recently, I’ve started to use WezTerm as my terminal over iTerm2 + tmux. I include tmux here because WezTerm has builtin tmux-like functionality as well.

Why the change

I’ve explored terminal emulators in Linux, macOS, and Windows before. On Windows, I found the Windows Terminal (in the store) to be adequate for that environment. In Linux, after experimenting with several options, I moved Alacritty. However, when I started to use macOS (I have my reasons), Alacritty didn’t quite meet my expectations. Despite its cross-platform nature, it lacked the familiar feel I’d grown accustomed to in Linux. This led me to adopt iTerm2, which I found satisfactory, especially when paired with tmux. iTerm2 served as my go-to terminal for quite some time. Recently, I discovered WezTerm, a new cross-platform terminal emulator written in Rust. I decided to give it a try. After using WezTerm for a while now, I can confidently say it has met my needs. If you’re considering trying it out, I’d recommend starting without tmux. In my experience, WezTerm inherently provides many of the features I previously relied on tmux for.

My Configuration

~/.config/wezterm/wezterm.lua

local wezterm = require 'wezterm'

local config = wezterm.config_builder()
local act = wezterm.action


config.color_scheme = 'Poimandres'
config.window_background_opacity = 0.9
config.macos_window_background_blur = 20
config.font = wezterm.font("JetBrains Mono", { weight = "Medium" })
config.font_size = 16
config.initial_rows = 45
config.initial_cols = 175

-- enable scroll bar
config.enable_scroll_bar = true
config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = true

-- adds effect to the inactive pane
config.inactive_pane_hsb = {
  saturation = 0.25,
  brightness = 0.5
}

config.scrollback_lines = 5000

-- configures whether the window has a title bar and/or resizable border.
config.window_decorations = "RESIZE"

config.default_workspace = "main"

-- disable right option and enable left option key for mac
config.send_composed_key_when_left_alt_is_pressed = true
config.send_composed_key_when_right_alt_is_pressed = false

-- my leader key is a, similar to tmux.
config.leader = { key = 'a', mods = 'CMD', timeout_milliseconds = 2000 }

-- key bindings
config.keys = {
  { key = 'c', mods = 'LEADER', action = act.ActivateCopyMode },
  { key = 'R', mods = 'SHIFT|CTRL', action = act.ReloadConfiguration },
  { key = '=', mods = 'LEADER', action = act.IncreaseFontSize },
  { key = '-', mods = 'CTRL', action = act.DecreaseFontSize },
  { key = '0', mods = 'CTRL', action = act.ResetFontSize },

  -- pane
  { key = '"', mods = 'LEADER', action = act.SplitVertical { domain = "CurrentPaneDomain" }},
  { key = '%', mods = 'LEADER', action = act.SplitHorizontal { domain = "CurrentPaneDomain" }},
  { key = 'h', mods = 'LEADER', action = act.ActivatePaneDirection("Left") },
  { key = 'j', mods = 'LEADER', action = act.ActivatePaneDirection("Down") },
  { key = 'k', mods = 'LEADER', action = act.ActivatePaneDirection("Up") },
  { key = 'l', mods = 'LEADER', action = act.ActivatePaneDirection("Right") },
  { key = 'x', mods = 'LEADER', action = act.CloseCurrentPane { confirm = true } },
  { key = 'z', mods = 'LEADER', action = act.TogglePaneZoomState },
  { key = 's', mods = 'LEADER', action = act.RotatePanes "Clockwise" },
  { key = 'v', mods = 'LEADER', action = act.ActivateKeyTable { name = "resize_pane", one_shot = false } },
  { key = "w", mods = "LEADER",       action = act.ShowLauncherArgs { flags = "FUZZY|WORKSPACES" } },

  -- tab
  { key = "t",          mods = "LEADER",      action = act.SpawnTab("CurrentPaneDomain") },
  { key = "[",          mods = "LEADER",      action = act.ActivateTabRelative(-1) },
  { key = "]",          mods = "LEADER",      action = act.ActivateTabRelative(1) },
  { key = "n",          mods = "LEADER",      action = act.ShowTabNavigator },
  -- rename tab
  {
    key = ",",
    mods = "LEADER",
    action = act.PromptInputLine {
      description = wezterm.format {
        { Attribute = { Intensity = "Bold" } },
        { Foreground = { AnsiColor = "Fuchsia" } },
        { Text = "Renaming Tab Title...:" },
      },
      action = wezterm.action_callback(function(window, pane, line)
        if line then
          window:active_tab():set_title(line)
        end
      end)
    }
  },
  -- Key table for moving tabs around
  { key = "m", mods = "LEADER",       action = act.ActivateKeyTable { name = "move_tab", one_shot = false } },
  { key = "{", mods = "LEADER|SHIFT", action = act.MoveTabRelative(-1) },
  { key = "}", mods = "LEADER|SHIFT", action = act.MoveTabRelative(1) },

  -- bind
  { key = "UpArrow", mods = "LEADER", action = act.ScrollByPage(-1) },
  { key = "DownArrow", mods = "LEADER", action = act.ScrollByPage(1) },
}

config.key_tables = {
  resize_pane = {
    { key = "h",      action = act.AdjustPaneSize { "Left", 1 } },
    { key = "j",      action = act.AdjustPaneSize { "Down", 1 } },
    { key = "k",      action = act.AdjustPaneSize { "Up", 1 } },
    { key = "l",      action = act.AdjustPaneSize { "Right", 1 } },
    { key = "Escape", action = "PopKeyTable" },
    { key = "Enter",  action = "PopKeyTable" },
  },
}

-- switch to tabs with index
for i = 1, 9 do
  table.insert(config.keys, {
    key = tostring(i),
    mods = "LEADER",
    action = act.ActivateTab(i - 1)
  })
end

return config

You can also the add status panel — I got the configuration below from theopn.

wezterm.on("update-status", function(window, pane)
  -- Workspace name
  local stat = window:active_workspace()
  local stat_color = "#f7768e"
  -- It's a little silly to have workspace name all the time
  -- Utilize this to display LDR or current key table name
  if window:active_key_table() then
    stat = window:active_key_table()
    stat_color = "#7dcfff"
  end
  if window:leader_is_active() then
    stat = "LDR"
    stat_color = "#bb9af7"
  end

  local basename = function(s)
    -- Nothing a little regex can't fix
    return string.gsub(s, "(.*[/\])(.*)", "%2")
  end

  -- Current working directory
  local cwd = pane:get_current_working_dir()
  if cwd then
    if type(cwd) == "userdata" then
      -- Wezterm introduced the URL object in 20240127-113634-bbcac864
      cwd = basename(cwd.file_path)
    else
      -- 20230712-072601-f4abf8fd or earlier version
      cwd = basename(cwd)
    end
  else
    cwd = ""
  end

  -- Current command
  local cmd = pane:get_foreground_process_name()
  -- CWD and CMD could be nil (e.g. viewing log using Ctrl-Alt-l)
  cmd = cmd and basename(cmd) or ""

  -- Time
  local time = wezterm.strftime("%H:%M")

  -- Left status (left of the tab line)
  window:set_left_status(wezterm.format({
    { Foreground = { Color = stat_color } },
    { Text = "  " },
    { Text = wezterm.nerdfonts.oct_table .. "  " .. stat },
    { Text = " |" },
  }))

  -- Right status
  window:set_right_status(wezterm.format({
    { Text = wezterm.nerdfonts.md_folder .. "  " .. cwd },
    { Text = " | " },
    { Foreground = { Color = "#e0af68" } },
    { Text = wezterm.nerdfonts.fa_code .. "  " .. cmd },
    "ResetAttributes",
    { Text = " | " },
    { Text = wezterm.nerdfonts.md_clock .. "  " .. time },
    { Text = "  " },
  }))
end)
Find an issue with this post? You can edit on github.