/PaperWM.spoon

Tiled scrollable window manager for MacOS

Primary LanguageLuaMIT LicenseMIT

PaperWM.spoon

Tiled scrollable window manager for MacOS. Inspired by PaperWM.

Spoon plugin for HammerSpoon MacOS automation app.

Demo

paperwm_spoon_demo.mp4

Installation

  1. Install the required hs.spaces module.

  2. Clone to ~/.hammerspoon/Spoons directory so init.lua from this repo is located at ~/.hammerspoon/Spoons/PaperWM.spoon/init.lua.

  3. Open System Preferences -> Mission Control. Uncheck "Automatically rearrange Spaces based on most recent use" and check "Displays have separate Spaces".

Screen Shot 2022-01-07 at 14 10 11

Usage

Add the following to your ~/.hammerspoon/init.lua:

PaperWM = hs.loadSpoon("PaperWM")
PaperWM:bindHotkeys({
    focus_left = { { "ctrl", "alt", "cmd" }, "h" },
    focus_right = { { "ctrl", "alt", "cmd" }, "l" },
    focus_up = { { "ctrl", "alt", "cmd" }, "k" },
    focus_down = { { "ctrl", "alt", "cmd" }, "j" },
    swap_left = { { "ctrl", "alt", "cmd", "shift" }, "h" },
    swap_right = { { "ctrl", "alt", "cmd", "shift" }, "l" },
    swap_up = { { "ctrl", "alt", "cmd", "shift" }, "k" },
    swap_down = { { "ctrl", "alt", "cmd", "shift" }, "j" },
    center_window = { { "ctrl", "alt", "cmd" }, "u" },
    full_width = { { "ctrl", "alt", "cmd" }, "f" },
    cycle_width = { { "ctrl", "alt", "cmd" }, "r" },
    cycle_height = { { "ctrl", "alt", "cmd", "shift" }, "r" },
    slurp_in = { { "ctrl", "alt", "cmd" }, "i" },
    barf_out = { { "ctrl", "alt", "cmd" }, "o" },
    switch_space_1 = { { "ctrl", "alt", "cmd" }, "1" },
    switch_space_2 = { { "ctrl", "alt", "cmd" }, "2" },
    switch_space_3 = { { "ctrl", "alt", "cmd" }, "3" },
    switch_space_4 = { { "ctrl", "alt", "cmd" }, "4" },
    switch_space_5 = { { "ctrl", "alt", "cmd" }, "5" },
    switch_space_6 = { { "ctrl", "alt", "cmd" }, "6" },
    switch_space_7 = { { "ctrl", "alt", "cmd" }, "7" },
    switch_space_8 = { { "ctrl", "alt", "cmd" }, "8" },
    switch_space_9 = { { "ctrl", "alt", "cmd" }, "9" },
    move_window_1 = { { "ctrl", "alt", "cmd", "shift" }, "1" },
    move_window_2 = { { "ctrl", "alt", "cmd", "shift" }, "2" },
    move_window_3 = { { "ctrl", "alt", "cmd", "shift" }, "3" },
    move_window_4 = { { "ctrl", "alt", "cmd", "shift" }, "4" },
    move_window_5 = { { "ctrl", "alt", "cmd", "shift" }, "5" },
    move_window_6 = { { "ctrl", "alt", "cmd", "shift" }, "6" },
    move_window_7 = { { "ctrl", "alt", "cmd", "shift" }, "7" },
    move_window_8 = { { "ctrl", "alt", "cmd", "shift" }, "8" },
    move_window_9 = { { "ctrl", "alt", "cmd", "shift" }, "9" },
})
PaperWM:start()

Feel free to customize hotkeys or use PaperWM:bindHotkeys(PaperWM.default_hotkeys) for defaults.

PaperWM:start() will begin automatically tiling new and existing windows. PaperWM:stop() will release control over windows.

Set PaperWM.window_gap to the number of pixels to space between windows and the top and bottom screen edges.

Overwrite PaperWM.window_filter to ignore specific applications. For example:

PaperWM.window_filter = PaperWM.window_filter:setAppFilter("Finder", false)
PaperWM:start() -- restart for new window filter to take effect

Limitations

MacOS does not allow a window to be moved fully off-screen. Windows that would be tiled off-screen are placed in a margin on the left and right edge of the screen. They are still visible and clickable.

It's difficult to detect when a window is dragged from one space or screen to another. Use the move_window_N commands to move windows between spaces and screens.

Arrange screens vertically to prevent windows from bleeding into other screens.

Screen Shot 2022-01-07 at 14 18 27