Skip to content

Instantly share code, notes, and snippets.

@cleverdevil
Created December 14, 2017 18:05
Show Gist options
  • Save cleverdevil/fd3e5f9eea3215547ea2c6492c0d3ee0 to your computer and use it in GitHub Desktop.
Save cleverdevil/fd3e5f9eea3215547ea2c6492c0d3ee0 to your computer and use it in GitHub Desktop.

Revisions

  1. cleverdevil created this gist Dec 14, 2017.
    203 changes: 203 additions & 0 deletions init.lua
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,203 @@
    -- -----------------
    -- Setup environment
    -- -----------------

    -- Animation off, mofo
    hs.window.animationDuration = 0

    -- Get list of screens and refresh that list whenever screens are (un)plugged
    local screens = hs.screen.allScreens()
    local screenwatcher = hs.screen.watcher.new(function()
    screens = hs.screen.allScreens()
    end)
    screenwatcher:start()

    -- Modifier shortcuts
    local hyper = {"", ""}
    local pushkey = {"", ""}

    -- Tracking variables
    local pressed = {
    up = false,
    down = false,
    left = false,
    right = false
    }

    -- Full screen sizes
    local fullScreenSizeIndex = 0
    local fullScreenSizes = {
    { x = 0.00, y = 0.00, w = 1.0, h = 1.0 },
    { x = 0.05, y = 0.05, w = 0.9, h = 0.9 },
    { x = 0.10, y = 0.10, w = 0.8, h = 0.8 },
    { x = 0.15, y = 0.15, w = 0.7, h = 0.7 },
    { x = 0.20, y = 0.20, w = 0.6, h = 0.6 },
    { x = 0.25, y = 0.25, w = 0.5, h = 0.5 }
    }


    -- ----------------
    -- Helper functions
    -- ----------------

    -- Resize window for chunk of screen.
    -- For x and y: use 0 to expand fully in that dimension, 0.5 to expand halfway
    -- For w and h: use 1 for full, 0.5 for half
    function push(x, y, w, h)
    local win = hs.window.focusedWindow()
    local f = win:frame()
    local screen = win:screen()
    local max = screen:frame()

    f.x = max.x + (max.w*x)
    f.y = max.y + (max.h*y)
    f.w = max.w*w
    f.h = max.h*h
    win:setFrame(f)
    end

    -- Shortcuts for pushing to top, bottom, left, right in every combination
    function pushT() push(0.0, 0.0, 1.0, 0.5) end
    function pushB() push(0.0, 0.5, 1.0, 0.5) end
    function pushL() push(0.0, 0.0, 0.5, 1.0) end
    function pushR() push(0.5, 0.0, 0.5, 1.0) end
    function pushTL() push(0.0, 0.0, 0.5, 0.5) end
    function pushTR() push(0.5, 0.0, 0.5, 0.5) end
    function pushBL() push(0.0, 0.5, 0.5, 0.5) end
    function pushBR() push(0.5, 0.5, 0.5, 0.5) end


    -- Move to monitor x. Checks to make sure monitor exists, if not moves to last monitor that exists
    function moveToMonitor(x)
    local win = hs.window.focusedWindow()
    local newScreen = nil
    while not newScreen do
    newScreen = screens[x]
    x = x-1
    end
    win:moveToScreen(newScreen)
    end

    -- -----------------
    -- Window management
    -- -----------------

    -- Push to left (including top left and bottom left)
    hs.hotkey.bind(pushkey, "left", function()
    pressed.left = true
    if pressed.up then
    pushTL()
    elseif pressed.down then
    pushBL()
    else
    pushL()
    end
    end, function ()
    pressed.left = false
    end)

    -- Push to right (including top right and bottom right)
    hs.hotkey.bind(pushkey, "right", function()
    pressed.right = true
    if pressed.up then
    pushTR()
    elseif pressed.down then
    pushBR()
    else
    pushR()
    end
    end, function()
    pressed.right = false
    end)

    -- Push to top (including top right and top left)
    hs.hotkey.bind(pushkey, "up", function()
    pressed.up = true
    if pressed.left then
    pushTL()
    elseif pressed.right then
    pushTR()
    else
    pushT()
    end
    end, function()
    pressed.up = false
    end)

    -- Push to bottom (including bottom left and bottom right)
    hs.hotkey.bind(pushkey, "down", function()
    pressed.down = true
    if pressed.left then
    pushBL()
    elseif pressed.right then
    pushBR()
    else
    pushB()
    end
    end, function()
    pressed.down = false
    end)

    -- Center window with some room to see the desktop
    hs.hotkey.bind(pushkey, "m", function() push(0.05,0.05,0.9,0.9) end)

    -- Move a window between monitors
    hs.hotkey.bind(pushkey, "1", function() moveToMonitor(1) end) -- Move to first monitor
    hs.hotkey.bind(pushkey, "2", function() moveToMonitor(2) end) -- Move to second monitor

    -- Tile windows on current screen
    hs.hotkey.bind({'cmd', 'ctrl'}, 't', function()
    local wins = hs.window.filter.new():setCurrentSpace(true):getWindows()
    local screen = hs.screen.mainScreen():currentMode()
    local rect = hs.geometry(0, 0, screen['w'], screen['h'])
    hs.window.tiling.tileWindows(wins, rect)
    end)


    -- -------------
    -- "Full" screen
    -- -------------

    -- Cycle through "full" screen sizes
    hs.hotkey.bind(pushkey, "f", function()
    fullScreenSizeIndex = fullScreenSizeIndex + 1
    if fullScreenSizeIndex > #fullScreenSizes then fullScreenSizeIndex = 1 end
    size = fullScreenSizes[fullScreenSizeIndex]
    push(size.x, size.y, size.w, size.h)
    end)

    -- Watch for focus changes to reset the full screen size cycling
    allwindows = hs.window.filter.new(nil)
    allwindows:subscribe(hs.window.filter.windowUnfocused, function () fullScreenSizeIndex = 0 end)


    -- ---------------------
    -- Application shortcuts
    -- ---------------------

    appmode = hs.hotkey.modal.new({"cmd"}, "E")
    appmode:bind({}, "B", function() hs.application.launchOrFocus("Safari") appmode:exit() end)
    appmode:bind({}, "T", function() hs.application.launchOrFocus("iTerm") appmode:exit() end)
    appmode:bind({}, "M", function() hs.application.launchOrFocus("Mail") appmode:exit() end)
    appmode:bind({}, "S", function() hs.application.launchOrFocus("Slack") appmode:exit() end)
    appmode:bind({}, "R", function() hs.application.launchOrFocus("Tweetbot") appmode:exit() end)
    appmode:bind({}, "I", function() hs.application.launchOrFocus("Messages") appmode:exit() end)

    -- -----------------------
    -- Configuration reloading
    -- -----------------------

    function reloadConfig(files)
    doReload = false
    for _,file in pairs(files) do
    if file:sub(-4) == ".lua" then
    doReload = true
    end
    end
    if doReload then
    hs.reload()
    end
    end

    hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reloadConfig):start()
    hs.alert.show("Config loaded")