Existential Risk Taxonomy

We shall use the following four categories to classify existential risks:

Bangs – Earth-originating intelligent life goes extinct in relatively sudden disaster resulting from either an accident or a deliberate act of destruction.

Crunches – The potential of humankind to develop into posthumanity is permanently thwarted although human life continues in some form.

Shrieks – Some form of posthumanity is attained but it is an extremely narrow band of what is possible and desirable.

Whimpers – A posthuman civilization arises but evolves in a direction that leads gradually but irrevocably to either the complete disappearance of the things we value or to a state where those things are realized to only a minuscule degree of what could have been achieved.

Nick Bostrom. March 02002.

Scripting Mjolnir: Quick Config Reloading

If you’re just joining us, you may want to start at the beginning with hello world.

If you’ve been following along by actually typing all this stuff into a text editor, you’ve probably gotten a little tired of having to switch to a mouse to click on the Mjolnir menu item, the click reload. And hope that no errors were found in your config.

So let’s make things a bit easier by adding a reload hotkey!

Looking through the Mjolnir docs, looks like mjolnir.reload() is the function we want.

So let’s try the simplest thing that could possibly work.

hotkey.bind({"cmd", "alt", "ctrl"}, "R", function()
  mjolnir.reload()
end)

Then for the last time, let’s reload the config with your mouse. Now you can just press Cmd+Alt+Ctrl+R any time you make a change.

Of course, it feels odd just having this happen in the background without any indicator of success. So let’s add a couple alerts to show what’s going on:

hotkey.bind({"cmd", "alt", "ctrl"}, "R", function()
  mjolnir.alert("reloading config")
  mjolnir.reload()
  mjolnir.alert("reloaded config")
end)

Then let’s reload the config once to get this updated hotkey loaded. Now reload again using the hotkey.

See anything wrong? No alerts? Yep, it’s surprising and it doesn’t work as you’d expect.

Turns out that what mjolnir.reload() does is destroy the existing lua environment and creates a new one. So the first alert is destroyed before you even notice it. And the rest of the function never gets executed.

So how do we get a notification? Well lua is a real scripting language, anything outside function definitions is executed just like a main() in a compiled language.

So let’s add the following to the top of the config:

mjolnir.alert("reloaded config")

Now every time Mjolnir loads the config, it’ll show this alert. Just reload (either with the hotkey or the menu item) and you should see that notification.

Scripting your Mac: Tiling Motion

If you’re just joining us, you may want to start at the beginning with hello world.

Now that we know how to move windows around on command, we can start implementing the basic window motions that SizeUp and Spectacle support.

Let’s start with the simplest case: full screen. I’m not talking about the native full screen mode provided by the operating system. Instead, we just want to expand the size of the window to fill the screen.

To do this, we’ll need to access the screen dimensions so we can appropriately scale the window’s width w and height h. The screen API is available through mjolnir.screen and it has a convenience function to get the screen of the currently focused window: mjolnir.screen.mainscreen(). Just like last time, we can grab the dimensions of the object by accessing its frame().

Of course, we’ll need to make sure the mjolnir.screen rock is installed along with the ones from last time:

luarocks install mjolnir.hotkey
luarocks install mjolnir.window
luarocks install mjolnir.screen

And we can make sure the window’s dimensions fill the screen by setting the window’s frame to have the same x, y, w & h as the screen’s frame:

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"
local screen = require "mjolnir.screen"

hotkey.bind({"cmd", "alt", "ctrl"}, "M", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w
  f.h = max.h
  win:setframe(f)
end)

As always, reload the config. Then try it out by pressing Cmd+Alt+Ctrl+M while uttering “embiggen!”

Next, let’s make windows snap to the left side of the screen. This should be relatively simple, we just need to make sure we have the width is half that of the screen, and otherwise should be identical to full screen.

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"
local screen = require "mjolnir.screen"

hotkey.bind({"cmd", "alt", "ctrl"}, "Left", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w / 2
  f.h = max.h
  win:setframe(f)
end)

And then we just need to flesh out the rest of the sides and corners to get:

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"
local screen = require "mjolnir.screen"

-- Tiling motions
hotkey.bind({"cmd", "alt", "ctrl"}, "M", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w
  f.h = max.h
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Left", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w / 2
  f.h = max.h
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Up", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w
  f.h = max.h / 2
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Right", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x + (max.w / 2)
  f.y = max.y
  f.w = max.w / 2
  f.h = max.h
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Down", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y + (max.h / 2)
  f.w = max.w
  f.h = max.h / 2
  win:setframe(f)
end)

Now you’ve got the chops to match any tiling motion that SizeUp or Spectacle can handle. Now let’s make development easier with quick config reloading.

Scripting your Mac: Basic Motion

If you’re just joining us, you may want to start at the beginning with hello world.

While that was fun, it’s not the most useful. Let’s start moving things around. Also, I’m going to make a point of explaining what’s going on from now on.

To move windows at your command, we’ll again need the mjolnir.hotkey rock. As you probably noticed, mjolnir.hotkey.bind() allows you to attach functions to key press and release events. This is how we’ll be triggering the window changes we want to make.

We’ll also need the mjolnir.window rock to give us access to the windows we want to control. We’ll be focusing on moving the currently active window, so we’ll access its window object with mjolnir.window.focusedwindow(). Then we’ll want to change it’s position on the screen, which is available as the rect object from mjolnir.window:frame(). Then we can fiddle with the x & y positions and save using mjolnir.window:setframe()!

So let’s begin by installing our dependencies:

luarocks install mjolnir.hotkey
luarocks install mjolnir.alert

Let’s begin with a tiny use case, just moving a window a bit to the left. Users of vi and nethack know that the only appropriate key bindings for this must use the H key. I’ll be assuming that you also don’t mind a bit of key mashing, so I’ll use Cmd+Alt+Ctrl as our mode. Here goes:

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"

hotkey.bind({"cmd", "alt", "ctrl"}, "H", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x - 10
  win:setframe(f)
end)

Seems simple enough right? The only thing to remember is that the origin of this Cartesian plane is in the upper left corner of the screen. So making x smaller means left, larger means right. And for y smaller means up, larger means down.

So let’s extend this control to the full nethack motion:

y k u
h l
b j n
local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"

-- Basic movement
-- y up-left
-- k up
-- u up-right
-- h leftgg
-- l right
-- b down-left
-- j down
-- n down-right

hotkey.bind({"cmd", "alt", "ctrl"}, "Y", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x - 10
  f.y = f.y - 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "K", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.y = f.y - 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "U", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x + 10
  f.y = f.y - 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "H", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x - 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "L", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x + 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "B", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x - 10
  f.y = f.y + 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "J", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.y = f.y + 10
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "N", function()
  local win = window.focusedwindow()
  local f = win:frame()

  f.x = f.x + 10
  f.y = f.y + 10
  win:setframe(f)
end)

Remember to reload your config!

And there you have it, basic motion for all cardinal and ordinal directions. With that under our belt, we’re ready to handle tiling motions.

Scripting your Mac: Getting started

I’m switching from Spectacle to Mjolnir mostly as an excuse to learn Lua. I’ve noticed that introductory documentation is a little sparing, so I figure I may as well start writing some.

If you’ve never programmed in Lua before, you may want to run through Learn Lua in Y minutes before you begin.

We’re going to work our way through building a subset of common tiling window managers like Spectacle and SizeUp.

First let’s build the traditional “Hello World!”.

We’ll need to install Mjolnir first, so download the latest release, move it into your Applications folder, and fire it up.

This example will need a couple libraries to work, so we’ll need to install the mjolnir.hotkey and mjolnir.alert rocks:

luarocks install mjolnir.hotkey
luarocks install mjolnir.alert

Then in your config (usually ~/.mjolnir/init.lua) file enter:

local hotkey = require "mjolnir.hotkey"
local alert = require "mjolnir.alert"

hotkey.bind({"cmd", "alt", "ctrl"}, "H", function()
  alert.show("Hello World!")
end)

Reload your config and press Cmd+Alt+Ctrl+H. You should see a bubble in the middle of the screen with the text “Hello World!”

Now that we understand the basic parts, we’re ready to move onto basic motion.

← Newer Page 1 of 6