New Year, New Terminal

I have been rocking mrxvt as my primary terminal emulator for what seems like 10 years. Coincidentally that is about the same amount of time since it was last updated. Simple, configurable, and most importantly speedy – mrxvt has been a reliable and faithful companion. For no particular reason except curiosity, and a bit of time around the holidays for tinkering, I decided to explore some other options.

To be clear, I spend the majority of my waking hours on a computer, and the majority of that at the command line, and the majority of that in vim. Swapping out the terminal part of that equation is not something I take lightly. This isn’t the first time I have ventured on this journey, but it is the first time I actually found a destination worth lingering on.

I started slogging through the old school contenders like so many times in the past, then I worked through the new-ish crop of terminals. I found some neat options, but nothing that quite fit the bill. Then I happened upon a long shot, a performance focused terminal called alacritty. By itself, allacritty did not have all the features I wanted, but paired with tmux, which it is intended to be used with, I thought it might just do the trick. Plus the project name is just to clever. Alacrity + TTY, I love it!

I have used screen in the past, and have heard of tmux, but basically had zero practical experience before the last few days. Turns out tmux is pretty sweet. Lots of knobs to twist, somewhat complicated to get setup the way I wanted, but not a vim level learning curve. Even more promising, I was able to massage tmux to behave like my custom mrxvt config. Big win for the old muscle memory.

Alacritty is a unique terminal emulator. It uses GPU accelerated rendering for speed, and has a very minimal, but smart, feature set. There are no Debian packages, so I had to compile from source. I have never built a program written in rust before, but it was as simple as apt-get installing a few pre-reqs, starting the build, and waiting for it to finish. While I was at it I built tmux from the latest git checkout, and installed the Hack font to replace the Terminus font I have been using for I don’t even know how long. I figure if I’m going new, may as well go new all the way. Well not all the way, I’m not switching to Emacs. That would be nuts!

One thing I LOVE about alacritty (aside from the speed), is the ability to map your own codes to keyboard combinations. I don’t use a lot of vim tweaks or plugins, but one thing I absolutely cannot do without is mapping “:wa” to Shift-Enter. It’s so handy! Some terminals just produce the same keycode for Enter when hitting Shift-Enter, but with allacritty I could easily setup a custom keycode that I could then map in my vimrc. Happy times!

Now I have UTF-8 support in the terminal, much improved HiDPI support for my laptop, and a slick fast terminal emulator with tabs and all the shortcuts I’m used to. It took about 2 days to tweak everything, but I’m going to use my new setup when I go back to work tomorrow and my dork excitement level is pretty high. I’m sure I will run into issues once I sink my teeth in, but I’m jazzed about starting 2018 with something new and improved (already LOVING tmux copy mode vs standard terminal scrollback (once I tweaked copy/paste)). I just nested parens, I love it when that happens!

Below are my .alacritty.yml and .tmux.conf files, and the obligatory screenshots of the before and after.

Old school


New school

.alacritty.yml (with few exceptions, this is the default alacritty config file)

# Configuration for Alacritty, the GPU enhanced terminal emulator


# Any items in the `env` entry below will be added as
# environment variables. Some entries may override variables
# set by alacritty it self.
env:
  # TERM env customization.
  #
  # If this property is not set, alacritty will set it to xterm-256color.
  #
  # Note that some xterm terminfo databases don't declare support for italics.
  # You can verify this by checking for the presence of `smso` and `sitm` in
  # `infocmp xterm-256color`.
  TERM: xterm-256color

window:
  # Window dimensions in character columns and lines
  # Falls back to size specified by window manager if set to 0x0.
  # (changes require restart)
  dimensions:
    columns: 80
    lines: 24

  # Adds this many blank pixels of padding around the window
  # Units are physical pixels; this is not DPI aware.
  # (change requires restart)
  padding:
    x: 20
    y: 20

  # Window decorations
  # Setting this to false will result in window without borders and title bar.
  decorations: false

# Display tabs using this many cells (changes require restart)
tabspaces: 8

# When true, bold text is drawn using the bright variant of colors.
draw_bold_text_with_bright_colors: true

# Font configuration (changes require restart)
#
# Important font attributes like antialiasing, subpixel aa, and hinting can be
# controlled through fontconfig. Specifically, the following attributes should
# have an effect:
#
# * hintstyle
# * antialias
# * lcdfilter
# * rgba
#
# For instance, if you wish to disable subpixel antialiasing, you might set the
# rgba property to "none". If you wish to completely disable antialiasing, you
# can set antialias to false.
#
# Please see these resources for more information on how to use fontconfig
#
# * https://wiki.archlinux.org/index.php/font_configuration#Fontconfig_configuration
# * file:///usr/share/doc/fontconfig/fontconfig-user.html
font:
  # The normal (roman) font face to use.
  normal:
    family: Hack # should be "Menlo" or something on macOS.
    # Style can be specified to pick a specific face.
    # style: Regular

  # The bold font face
  bold:
    family: monospace # should be "Menlo" or something on macOS.
    # Style can be specified to pick a specific face.
    style: Regular

  # The italic font face
  italic:
    family: monospace # should be "Menlo" or something on macOS.
    # Style can be specified to pick a specific face.
    # style: Italic

  # Point size of the font
  size: 10.0

  # Offset is the extra space around each character. offset.y can be thought of
  # as modifying the linespacing, and offset.x as modifying the letter spacing.
  offset:
    x: 0.0
    y: 0.0

  # Glyph offset determines the locations of the glyphs within their cells with
  # the default being at the bottom. Increase the x offset to move the glyph to
  # the right, increase the y offset to move the glyph upward.
  glyph_offset:
    x: 0.0
    y: 0.0

  # OS X only: use thin stroke font rendering. Thin strokes are suitable
  # for retina displays, but for non-retina you probably want this set to
  # false.
  use_thin_strokes: true

# Should display the render timer
render_timer: false

# Use custom cursor colors. If true, display the cursor in the cursor.foreground
# and cursor.background colors, otherwise invert the colors of the cursor.
custom_cursor_colors: true

# Colors (Tomorrow Night Bright)
colors:
  # Default colors
  primary:
    background: '0x000000'
    foreground: '0xeaeaea'

  # Colors the cursor will use if `custom_cursor_colors` is true
  cursor:
    text: '0x000000'
    cursor: '0x888888'

  # Normal colors
  normal:
    black:   '0x000000'
    red:     '0xd54e53'
    green:   '0xb9ca4a'
    yellow:  '0xe6c547'
    blue:    '0x7aa6da'
    magenta: '0xc397d8'
    cyan:    '0x70c0ba'
    white:   '0xffffff'

  # Bright colors
  bright:
    black:   '0x666666'
    red:     '0xff3334'
    green:   '0x9ec400'
    yellow:  '0xe7c547'
    blue:    '0x7aa6da'
    magenta: '0xb77ee0'
    cyan:    '0x54ced6'
    white:   '0xffffff'

  # Dim colors (Optional)
  dim:
    black:   '0x333333'
    red:     '0xf2777a'
    green:   '0x99cc99'
    yellow:  '0xffcc66'
    blue:    '0x6699cc'
    magenta: '0xcc99cc'
    cyan:    '0x66cccc'
    white:   '0xdddddd'

# Visual Bell
#
# Any time the BEL code is received, Alacritty "rings" the visual bell. Once
# rung, the terminal background will be set to white and transition back to the
# default background color. You can control the rate of this transition by
# setting the `duration` property (represented in milliseconds). You can also
# configure the transition function by setting the `animation` property.
#
# Possible values for `animation`
# `Ease`
# `EaseOut`
# `EaseOutSine`
# `EaseOutQuad`
# `EaseOutCubic`
# `EaseOutQuart`
# `EaseOutQuint`
# `EaseOutExpo`
# `EaseOutCirc`
# `Linear`
#
# To completely disable the visual bell, set its duration to 0.
#
visual_bell:
  animation: EaseOutExpo
  duration: 0

# Background opacity
background_opacity: 1.0

# Mouse bindings
#
# Currently doesn't support modifiers. Both the `mouse` and `action` fields must
# be specified.
#
# Values for `mouse`:
# - Middle
# - Left
# - Right
# - Numeric identifier such as `5`
#
# Values for `action`:
# - Paste
# - PasteSelection
# - Copy (TODO)
mouse_bindings:
  - { mouse: Middle, action: PasteSelection }

mouse:
  double_click: { threshold: 300 }
  triple_click: { threshold: 300 }

selection:
    semantic_escape_chars: ",│`|:\"' ()[]{}"

dynamic_title: true

hide_cursor_when_typing: true

# Style of the cursor
#
# Values for 'cursor_style':
# - Block
# - Underline
# - Beam
cursor_style: Block

# Live config reload (changes require restart)
live_config_reload: true

# Shell
#
# You can set shell.program to the path of your favorite shell, e.g. /bin/fish.
# Entries in shell.args are passed unmodified as arguments to the shell.
# shell:
#   program: /bin/bash
#   args:
#     - --login


# Key bindings
#
# Each binding is defined as an object with some properties. Most of the
# properties are optional. All of the alphabetical keys should have a letter for
# the `key` value such as `V`. Function keys are probably what you would expect
# as well (F1, F2, ..). The number keys above the main keyboard are encoded as
# `Key1`, `Key2`, etc. Keys on the number pad are encoded `Number1`, `Number2`,
# etc.  These all match the glutin::VirtualKeyCode variants.
#
# Possible values for `mods`
# `Command`, `Super` refer to the super/command/windows key
# `Control` for the control key
# `Shift` for the Shift key
# `Alt` and `Option` refer to alt/option
#
# mods may be combined with a `|`. For example, requiring control and shift
# looks like:
#
# mods: Control|Shift
#
# The parser is currently quite sensitive to whitespace and capitalization -
# capitalization must match exactly, and piped items must not have whitespace
# around them.
#
# Either an `action`, `chars`, or `command` field must be present.
#   `action` must be one of `Paste`, `PasteSelection`, `Copy`, or `Quit`.
#   `chars` writes the specified string every time that binding is activated.
#     These should generally be escape sequences, but they can be configured to
#     send arbitrary strings of bytes.
#   `command` must be a map containing a `program` string, and `args` array of
#     strings. For example:
#     - { ... , command: { program: "alacritty", args: ["-e", "vttest"] } }
#
# Want to add a binding (e.g. "PageUp") but are unsure what the X sequence
# (e.g. "\x1b[5~") is? Open another terminal (like xterm) without tmux,
# then run `showkey -a` to get the sequence associated to a key combination.
key_bindings:
  - { key: V,        mods: Control|Shift,    action: Paste               }
  - { key: C,        mods: Control|Shift,    action: Copy                }
  - { key: Q,        mods: Command, action: Quit                         }
  - { key: W,        mods: Command, action: Quit                         }
  - { key: Insert,   mods: Shift,   action: PasteSelection               }
  - { key: Key0,     mods: Control, action: ResetFontSize                }
  - { key: Equals,   mods: Control, action: IncreaseFontSize             }
  - { key: Subtract, mods: Control, action: DecreaseFontSize             }
  - { key: Home,                    chars: "\x1bOH",   mode: AppCursor   }
  - { key: Home,                    chars: "\x1b[H",   mode: ~AppCursor  }
  - { key: End,                     chars: "\x1bOF",   mode: AppCursor   }
  - { key: End,                     chars: "\x1b[F",   mode: ~AppCursor  }
  - { key: PageUp,   mods: Shift,   chars: "\x1b[5;2~"                   }
  - { key: PageUp,   mods: Control, chars: "\x1b[5;5~"                   }
  - { key: PageUp,                  chars: "\x1b[5~"                     }
  - { key: PageDown, mods: Shift,   chars: "\x1b[6;2~"                   }
  - { key: PageDown, mods: Control, chars: "\x1b[6;5~"                   }
  - { key: PageDown,                chars: "\x1b[6~"                     }
  - { key: Tab,      mods: Shift,   chars: "\x1b[Z"                      }
  - { key: Back,                    chars: "\x7f"                        }
  - { key: Back,     mods: Alt,     chars: "\x1b\x7f"                    }
  - { key: Insert,                  chars: "\x1b[2~"                     }
  - { key: Delete,                  chars: "\x1b[3~"                     }
  - { key: Left,     mods: Shift,   chars: "\x1b[1;2D"                   }
  - { key: Left,     mods: Control, chars: "\x1b[1;5D"                   }
  - { key: Left,     mods: Alt,     chars: "\x1b[1;3D"                   }
  - { key: Left,                    chars: "\x1b[D",   mode: ~AppCursor  }
  - { key: Left,                    chars: "\x1bOD",   mode: AppCursor   }
  - { key: Right,    mods: Shift,   chars: "\x1b[1;2C"                   }
  - { key: Right,    mods: Control, chars: "\x1b[1;5C"                   }
  - { key: Right,    mods: Alt,     chars: "\x1b[1;3C"                   }
  - { key: Right,                   chars: "\x1b[C",   mode: ~AppCursor  }
  - { key: Right,                   chars: "\x1bOC",   mode: AppCursor   }
  - { key: Up,       mods: Shift,   chars: "\x1b[1;2A"                   }
  - { key: Up,       mods: Control, chars: "\x1b[1;5A"                   }
  - { key: Up,       mods: Alt,     chars: "\x1b[1;3A"                   }
  - { key: Up,                      chars: "\x1b[A",   mode: ~AppCursor  }
  - { key: Up,                      chars: "\x1bOA",   mode: AppCursor   }
  - { key: Down,     mods: Shift,   chars: "\x1b[1;2B"                   }
  - { key: Down,     mods: Control, chars: "\x1b[1;5B"                   }
  - { key: Down,     mods: Alt,     chars: "\x1b[1;3B"                   }
  - { key: Down,                    chars: "\x1b[B",   mode: ~AppCursor  }
  - { key: Down,                    chars: "\x1bOB",   mode: AppCursor   }
  - { key: F1,                      chars: "\x1bOP"                      }
  - { key: F2,                      chars: "\x1bOQ"                      }
  - { key: F3,                      chars: "\x1bOR"                      }
  - { key: F4,                      chars: "\x1bOS"                      }
  - { key: F5,                      chars: "\x1b[15~"                    }
  - { key: F6,                      chars: "\x1b[17~"                    }
  - { key: F7,                      chars: "\x1b[18~"                    }
  - { key: F8,                      chars: "\x1b[19~"                    }
  - { key: F9,                      chars: "\x1b[20~"                    }
  - { key: F10,                     chars: "\x1b[21~"                    }
  - { key: F11,                     chars: "\x1b[23~"                    }
  - { key: F12,                     chars: "\x1b[24~"                    }
  - { key: F1,       mods: Shift,   chars: "\x1b[1;2P"                   }
  - { key: F2,       mods: Shift,   chars: "\x1b[1;2Q"                   }
  - { key: F3,       mods: Shift,   chars: "\x1b[1;2R"                   }
  - { key: F4,       mods: Shift,   chars: "\x1b[1;2S"                   }
  - { key: F5,       mods: Shift,   chars: "\x1b[15;2~"                  }
  - { key: F6,       mods: Shift,   chars: "\x1b[17;2~"                  }
  - { key: F7,       mods: Shift,   chars: "\x1b[18;2~"                  }
  - { key: F8,       mods: Shift,   chars: "\x1b[19;2~"                  }
  - { key: F9,       mods: Shift,   chars: "\x1b[20;2~"                  }
  - { key: F10,      mods: Shift,   chars: "\x1b[21;2~"                  }
  - { key: F11,      mods: Shift,   chars: "\x1b[23;2~"                  }
  - { key: F12,      mods: Shift,   chars: "\x1b[24;2~"                  }
  - { key: F1,       mods: Control, chars: "\x1b[1;5P"                   }
  - { key: F2,       mods: Control, chars: "\x1b[1;5Q"                   }
  - { key: F3,       mods: Control, chars: "\x1b[1;5R"                   }
  - { key: F4,       mods: Control, chars: "\x1b[1;5S"                   }
  - { key: F5,       mods: Control, chars: "\x1b[15;5~"                  }
  - { key: F6,       mods: Control, chars: "\x1b[17;5~"                  }
  - { key: F7,       mods: Control, chars: "\x1b[18;5~"                  }
  - { key: F8,       mods: Control, chars: "\x1b[19;5~"                  }
  - { key: F9,       mods: Control, chars: "\x1b[20;5~"                  }
  - { key: F10,      mods: Control, chars: "\x1b[21;5~"                  }
  - { key: F11,      mods: Control, chars: "\x1b[23;5~"                  }
  - { key: F12,      mods: Control, chars: "\x1b[24;5~"                  }
  - { key: F1,       mods: Alt,     chars: "\x1b[1;6P"                   }
  - { key: F2,       mods: Alt,     chars: "\x1b[1;6Q"                   }
  - { key: F3,       mods: Alt,     chars: "\x1b[1;6R"                   }
  - { key: F4,       mods: Alt,     chars: "\x1b[1;6S"                   }
  - { key: F5,       mods: Alt,     chars: "\x1b[15;6~"                  }
  - { key: F6,       mods: Alt,     chars: "\x1b[17;6~"                  }
  - { key: F7,       mods: Alt,     chars: "\x1b[18;6~"                  }
  - { key: F8,       mods: Alt,     chars: "\x1b[19;6~"                  }
  - { key: F9,       mods: Alt,     chars: "\x1b[20;6~"                  }
  - { key: F10,      mods: Alt,     chars: "\x1b[21;6~"                  }
  - { key: F11,      mods: Alt,     chars: "\x1b[23;6~"                  }
  - { key: F12,      mods: Alt,     chars: "\x1b[24;6~"                  }
  - { key: F1,       mods: Super,   chars: "\x1b[1;3P"                   }
  - { key: F2,       mods: Super,   chars: "\x1b[1;3Q"                   }
  - { key: F3,       mods: Super,   chars: "\x1b[1;3R"                   }
  - { key: F4,       mods: Super,   chars: "\x1b[1;3S"                   }
  - { key: F5,       mods: Super,   chars: "\x1b[15;3~"                  }
  - { key: F6,       mods: Super,   chars: "\x1b[17;3~"                  }
  - { key: F7,       mods: Super,   chars: "\x1b[18;3~"                  }
  - { key: F8,       mods: Super,   chars: "\x1b[19;3~"                  }
  - { key: F9,       mods: Super,   chars: "\x1b[20;3~"                  }
  - { key: F10,      mods: Super,   chars: "\x1b[21;3~"                  }
  - { key: F11,      mods: Super,   chars: "\x1b[23;3~"                  }
  - { key: F12,      mods: Super,   chars: "\x1b[24;3~"                  }
  - { key: Return,   mods: Shift,   chars: "\x1b[25;3~"                  }

.tmux.conf (this was mashed up from a bunch of different google-able tmux examples)

setw -g mode-keys vi
set -g mouse on
set -g terminal-overrides 'xterm*:smcup@:rmcup@'
set-option -g visual-activity off
set-option -g visual-bell off
set-option -g visual-silence off
set-window-option -g monitor-activity off
set-option -g bell-action none
set-window-option -g word-separators ' '

bind -n S-Left previous-window
bind -n S-Right next-window
bind -n S-Up select-pane -U
bind -n S-Down select-pane -D
bind -n C-h split-window -v
bind -n S-PageUp copy-mode
bind -n C-n new-window \; \
    setw -g force-height 63

bind-key -T copy-mode-vi DoubleClick1Pane \
    select-pane \; \
    send-keys -X select-word \; \
    send-keys -X copy-pipe "xclip" \

bind-key -n DoubleClick1Pane \
    select-pane \; \
    copy-mode -M \; \
    send-keys -X select-word \; \
    send-keys -X copy-pipe "xclip" \; \
    display-message "COPIED"

bind-key -T copy-mode-vi \
    y send-keys -X \
    copy-pipe-and-cancel "xclip" \; \
    display-message "COPIED"

bind-key -T copy-mode-vi \
    MouseDragEnd1Pane \
    send-keys -X \
    copy-pipe-and-cancel \
    "xclip" \; \
    display-message "COPIED"

set -g pane-border-fg black
set -g pane-active-border-fg brightred
set -g status-justify left
set -g status-bg default
set -g status-fg colour12
set -g status-interval 2
set -g message-fg black
set -g message-bg yellow
set -g message-command-fg blue
set -g message-command-bg black
setw -g mode-bg colour6
setw -g mode-fg colour0
setw -g force-height 63
setw -g window-status-format " #F#I:#W#F "
setw -g window-status-current-format " #F#I:#W#F "
setw -g window-status-format "#[fg=magenta]#[bg=black] #I #[bg=cyan]#[fg=colour8] #W "
setw -g window-status-current-format "#[bg=brightmagenta]#[fg=colour8] #I #[fg=colour8]#[bg=colour14] #W "
setw -g window-status-current-bg colour0
setw -g window-status-current-fg colour11
setw -g window-status-current-attr dim
setw -g window-status-bg green
setw -g window-status-fg black
setw -g window-status-attr reverse
set -g status-left ''
set -g default-terminal "screen-256color"
setw -g clock-mode-colour colour135
setw -g mode-attr bold
setw -g mode-fg colour17
setw -g mode-bg colour238
set -g pane-border-bg colour0
set -g pane-border-fg colour0
set -g pane-active-border-bg colour0
set -g pane-active-border-fg colour0
set -g status-position bottom
set -g status-bg colour233
set -g status-fg colour4
set -g status-attr dim
set -g status-left ''
set -g status-right ''
set -g status-right-length 50
set -g status-left-length 20
setw -g window-status-current-fg colour81
setw -g window-status-current-bg colour238
setw -g window-status-current-attr bold
setw -g window-status-current-format ' #I#[fg=colour250]:#[fg=colour255]#W#[fg=colour50]#F '
setw -g window-status-fg colour138
setw -g window-status-bg colour235
setw -g window-status-attr none
setw -g window-status-format ' #I#[fg=colour237]:#[fg=colour250]#W#[fg=colour244]#F '
setw -g window-status-bell-attr bold
setw -g window-status-bell-fg colour255
setw -g window-status-bell-bg colour1
set -g message-attr bold
set -g message-fg colour250
set -g message-bg colour234

I want to wish all unencumbered readers out there a happy New Year, and I hope this next year brings all of you good fortune. I also want to thank Farmobile (my employer), for giving us the last week off. Without it I would not have had the time to get my geek on and make this update possible. I almost can’t wait to go back to work tomorrow!

One thought on “New Year, New Terminal

  1. Pingback: I’ll Be ABAC – Unencumbered by Facts

Leave a comment