Jonas Helgemo

April 14, 2021

Alacritty Drop down/Guake/Quake-style terminal setup on MacOS ⚡

EDIT: It seems that this is not the correct way to set this up anymore. For the new way of doing this check this gist comment:

 https://gist.github.com/programus/d3bf9c6b8f9b7648891d1f59b665b35e#gistcomment-4730779


I ❤️ my terminal

As a programmer I spend a good chunk of my working day in a terminal and have up until recently used iTerm2 for MacOS. It is pretty nice, but I also use tmux (if you haven't heard about it, check it out immediately). Using tmux I have no need for all the extra crap that is bundled into iTerm2 like tabs, panes, keyboard shortcuts, paste history, as this is handled by tmux in a standard manner everywhere I use a terminal. One feature that I really liked though, was support for a Guake-style terminal (also called HUD or Quake style named after the game), you know the one that slides over the active window from the top of the screen.

I have had my eye on Alacritty for a while. It seems to tick every box that I'm looking for in a good terminal emulator. It's minimal with no extra bells and whistles and it's really fast (no surprise, it's written in Rust). I tested it a few years ago, and it looked promising, but was way to buggy back then. A few days ago I had a really frustrating day with iTerm2, so I decided to give Alacritty another try, and wow, what a difference. Alacritty feels stable as a rock, and the performance is off the charts. The only thing that was missing was the sweet Guake-style terminal that I had gotten used to with iTerm2, I'm totally dependent on being able to bring up a terminal on any screen with a keyboard shortcut. After some research, I found the perfect solution using a combination of the Alacritty config and hammerspoon. 

Ok, enough already, show me how!

I have to admit that my solution was heavily inspired by this amazing gist with a few minor tweaks. A longer discussion on other options in this issue as well: https://github.com/alacritty/alacritty/issues/862

Step 1: Install the dependencies (I use Homebrew):

brew install alacritty hammerspoon

Step 2: Configure Alacritty

~/.config/alacritty.yml:

window:
  # Window dimensions (changes require restart)
  #
  # Number of lines/columns (not pixels) in the terminal. The number of columns
  # must be at least `2`, while using a value of `0` for columns and lines will
  # fall back to the window manager's recommended size.
  dimensions:
    columns: 500
    lines: 30

  # Window position (changes require restart)
  #
  # Specified in number of pixels.
  # If the position is not set, the window manager will handle the placement.
  position:
    x: 0
    y: 0

  # Window padding (changes require restart)
  #
  # Blank space added around the window in pixels. This padding is scaled
  # by DPI and the specified value is always added at both opposing sides.
  #padding:
  #  x: 0
  #  y: 0

  # Spread additional padding evenly around the terminal content.
  #dynamic_padding: false

  # Window decorations
  #
  # Values for `decorations`:
  #     - full: Borders and title bar
  #     - none: Neither borders nor title bar
  #
  # Values for `decorations` (macOS only):
  #     - transparent: Title bar, transparent background and title bar buttons
  #     - buttonless: Title bar, transparent background and no title bar buttons
  decorations: none
  
key_bindings:
  - { key: Return,          mods: Command,                    action: ToggleSimpleFullscreen }


Step 3: Configure Hammerspoon

First, install this: https://github.com/asmagill/hs._asm.undocumented.spaces

~/.hammerspoon/init.lua:

-- https://github.com/asmagill/hs._asm.undocumented.spaces
local spaces = require "hs.spaces"
local screen = require "hs.screen"

-- Switch alacritty
hs.hotkey.bind({'alt','shift','ctrl'}, 'j', function ()
  local APP_NAME = 'Alacritty'
  function moveWindow(alacritty, space)
    -- move to main space
    local win = nil
    while win == nil do
      win = alacritty:mainWindow()
    end
    print("win = ", win)
    print("space = ", space)
    print("win:screen() = ", win:screen())
    local fullScreen = not win:isStandard()
    if fullScreen then
      hs.eventtap.keyStroke('cmd', 'return', 0, alacritty)
    end
    winFrame = win:frame()
    scrFrame = screen.mainScreen():frame()
    print(winFrame)
    print(scrFrame)
    winFrame.w = scrFrame.w
    winFrame.y = scrFrame.y
    winFrame.x = scrFrame.x
    print(winFrame)
    win:setFrame(winFrame, 0)
    print(win:frame())
    spaces.moveWindowToSpace(win, space)
    if fullScreen then
      hs.eventtap.keyStroke('cmd', 'return', 0, alacritty)
    end
    win:focus()
  end
  local alacritty = hs.application.get(APP_NAME)
  if alacritty ~= nil and alacritty:isFrontmost() then
    alacritty:hide()
  else
    local space = spaces.activeSpaceOnScreen()
    print("activeSpace() = ", space)
    if alacritty == nil and hs.application.launchOrFocus(APP_NAME) then
      local appWatcher = nil
      print('create app watcher')
      appWatcher = hs.application.watcher.new(function(name, event, app)
        print(name)
        print(event)
        if event == hs.application.watcher.launched and name == APP_NAME then
          app:hide()
          moveWindow(app, space)
          appWatcher:stop()
        end
      end)
      print('start watcher')
      appWatcher:start()
    end
    if alacritty ~= nil then
      moveWindow(alacritty, space)
    end
  end
end)

-- Hide alacritty if not in focus
-- hs.window.filter.default:subscribe(hs.window.filter.windowFocused, function(window, appName)
--   local alacritty = hs.application.get('Alacritty')
--   print(alacritty)
--   if alacritty ~= nil then
--      print('hiding alacritty')
--      alacritty:hide()
--   end
-- end)


Step 4: Take it for a spin using the shortcut from Hammerspoon 🎉

You should now have a blazing fast terminal right at your fingertips that you can show and hide on any screen or space, even if apps are in fullscreen. You're welcome 😎

NB: If you want the terminal to fill the screen, you just configured a shortcut for this Command-Enter. 

About Jonas Helgemo

Practitioner of the dark arts and bass player

🌐 https://jhel.no