Home

Awesome

Wezmode

Modal keybinds and prompts for wezterm

NOTICE: I've since decided to take development of this plugin more seriously. As a result, please consider it to be pre-release. Things may (will) change. And they may (probably) break. I will treat version 3.0.0 as the first stable release to avoid changing the versions of older releases. For now, the docs below refer to version 2.

What is it?

A super simple set of helper methods (plugin?) to create custom "modes" using the key_tables functionality of wezterm.

Here's a few of my modes: normal mode pane mode resize mode

Table of Contents

  1. Limitations
  2. Installation
  3. Usage
  4. Advanced Usage
  5. Full config example
<a name="limitations"/>

Limitations

Using this plugin, we decide on a modifier and a set of keys that will trigger certain modes. By default, CTRL is the modifier. There is currently no way to have different modes under different modifiers.

There is currently no way to have nested modes. This feature is on the roadmap.

<a name="installation"/>

Installation

To install this script, place wezmode.lua from the latest release in your wezterm config directory. This is usually $HOME/.config/wezterm

Once the script is installed. Sweet nothing will happen. Let's move on to usage.

<a name="usage"/>

Usage

-- wezterm.lua
local wezterm = require("wezterm")

-- 1. Import wezmode into your `wezterm.lua` config.
local wezmode = require("wezmode")

-- 2. Call the setup function to generate your keymaps,
     -- key tables and mode texts (The text in the status bar)
wezmode.setup({
  {
     name = "pane", -- the name that will show in the status bar for the mode
     key = "p", -- the key you'll use with your modifier to enter the mode
     modeColor = "#89b4fa", -- the color of the mode indicator
     keyTable = {
       {
          key = "r",
          desc = "right",
          action = wezterm.action.SplitHorizontal({ domain = "CurrentPaneDomain" })
        },
        -- more keybinds here
    }
  },
  -- some more modes here
})

-- 3. Set up the right status text to use our modes
wezmode.handleRightStatusUpdate()

-- 4. Add our modes to our wezterm config
return {
    -- other config options
    keys = wezmode.getKeys(),
    key_tables = wezmode.getKeyTables(),
}

See the next section (Advanced usage) for more complex configurations.

<a name="advanced"/>

Advanced usage

<a name="advanced.config"/>

Config

An optional config can be supplied as the second argument for wezmode.setup The default config is as follows:

{
  modifier = "CTRL", -- follows the same modifier syntax as wezterm key maps
  hintSeparator = "/", -- the character that separates each hint
  theme = {
    normalModeColor = "red", -- the color to use for the normal mode indicator
    hintColor = "green", -- the color to use for the key hints
    modeTextColor = "black", -- the text color for the mode indicators
    textColor = "white", -- the basic text color
  }
}

For example if we want to use Ctrl & Alt for our modifier:

wezmode.setup({
  -- modes here as usual
},
{
  modifier = "CTRL|ALT"
})

This plugin also supports HYPER, HYP & MEH as modifiers. Under the hood they expand to CMD|ALT|CTRL|SHIFT and ALT|CTRL|SHIFT respectively. The modifier hint will show the "shortcut" text rather than the expanded modifier.

<a name="advanced.merging"/>

Merging with existing keymaps

By using only wezmode.getKeys and wezmode.getKeyMaps to set our keybinds, we are limited to using bindings only defined in our wezmode.setup call. To use other key maps we can use wezmode.extendTable. For example if we wanted to use ALT+Arrow Keys to navigate between panes as well as use our mode config:

-- wezterm.lua
return {
  -- the rest of your config...
  keys = wezmode.extendTable({
        { mods = "ALT", key = "LeftArrow", action = wezterm.action { ActivatePaneDirection = "Left" } },
        { mods = "ALT", key = "RightArrow", action = wezterm.action { ActivatePaneDirection = "Right" } },
        { mods = "ALT", key = "UpArrow", action = wezterm.action { ActivatePaneDirection = "Up" } },
        { mods = "ALT", key = "DownArrow", action = wezterm.action { ActivatePaneDirection = "Down" } },
     }, wezmode.getKeys()),
  -- extendTable can also work with `key_tables`
}
<a name="advanced.status"/>

Manually setting the status

If you want to get the text used in the status to set it manually we can use wezmode.getModeText.

For example let's remove the call to wezmode.handleRightStatusUpdate and replace it with:

wezterm.on('update-right-statuis', function(window)
    window:set_right_status(wezmode.getModeText(window:active_key_table() or "normal"))
end)

This will behave the same as wezmode.handleRightStatusUpdate but allows us to extend the behavior or use the mode text in other ways.

<a name="config_example"/>

Full wezterm.lua config example

local wezterm = require('wezterm')
local wezmode = require("wezmode")

-- custom vars
local resize_amount = 3;

local wezmodeConfig = {
  theme = {
    textColor = "white",
    hintColor = "#a6e3a1",
    normalModeColor = "#cba6f7",
    modeTextColor = "#11111b",
  }
}

wezmode.setup({
  {
    name = "pane",
    key = "p",
    modeColor = "#89b4fa",
    keyTable = {
      { key = "r", desc = "right", action = wezterm.action.SplitHorizontal({ domain = "CurrentPaneDomain" }) },
      { key = "n", desc = "new", action = wezterm.action.SplitHorizontal({ domain = "CurrentPaneDomain" }) },
      { key = "d", desc = "down", action = wezterm.action.SplitVertical({ domain = "CurrentPaneDomain" }) },
      { key = "x", desc = "close", action = wezterm.action.CloseCurrentPane({ confirm = false }) },
      { key = "s", desc = "select", action = wezterm.action.PaneSelect },
      -- Cancel the mode by pressing escape
      { key = "Escape", desc = "back", action = "PopKeyTable" },
    }
  },
  {
    name = "resize",
    key = "n",
    modeColor = "#fab387",
    keyTable = {
      { key = "h", desc = "left", action = wezterm.action.AdjustPaneSize({ "Left", resize_amount }) },
      { key = "l", desc = "right", action = wezterm.action.AdjustPaneSize({ "Right", resize_amount }) },
      { key = "k", desc = "up", action = wezterm.action.AdjustPaneSize({ "Up", resize_amount }) },
      { key = "j", desc = "down", action = wezterm.action.AdjustPaneSize({ "Down", resize_amount }) },
      -- Cancel the mode by pressing escape
      { key = "Escape", desc = "back", action = "PopKeyTable" },
    },
  },
  {
    name = "move",
    key = "h",
    modeColor = "#f38ba8",
    keyTable = {
      { key = "n", desc = "Rotate next", action = wezterm.action.RotatePanes('Clockwise') },
      -- Cancel the mode by pressing escape
      { key = "Escape", desc = "back", action = "PopKeyTable" },
    }
  },
  {
    name = "tab",
    key = "t",
    modeColor = "#a6e3a1",
    keyTable = {
      { key = "n", desc = "new", action = wezterm.action.SpawnTab("CurrentPaneDomain") },
      { key = "h", desc = "left", action = wezterm.action.ActivateTabRelative(-1) },
      { key = "l", desc = "right", action = wezterm.action.ActivateTabRelative(1) },
      { key = "x", desc = "close", action = wezterm.action.CloseCurrentTab({ confirm = false }) },
      -- Cancel the mode by pressing escape
      { key = "Escape", desc = "back", action = "PopKeyTable" },
    }
  }
}, wezmodeConfig)

wezmode.handleRightStatusUpdate()

return {
  font = wezterm.font("VictorMono Nerd Font Mono", { weight = "DemiBold" }),
  use_fancy_tab_bar = false,
  tab_max_width = 50,
  window_padding = { left = 4, right = 2, top = 1, bottom = 0 },
  font_size = 15,
  keys = wezmode.extendTable({
    -- pane moving
    { mods = "ALT", key = "LeftArrow", action = wezterm.action { ActivatePaneDirection = "Left" } },
    { mods = "ALT", key = "RightArrow", action = wezterm.action { ActivatePaneDirection = "Right" } },
    { mods = "ALT", key = "UpArrow", action = wezterm.action { ActivatePaneDirection = "Up" } },
    { mods = "ALT", key = "DownArrow", action = wezterm.action { ActivatePaneDirection = "Down" } },
  }, wezmode.getKeys()),
  key_tables = wezmode.getKeyTables(),
}