diff --git a/hammerspoon/hs/tiling/init.lua b/hammerspoon/hs/tiling/init.lua deleted file mode 100755 index b1ce2020..00000000 --- a/hammerspoon/hs/tiling/init.lua +++ /dev/null @@ -1,195 +0,0 @@ -local tiling = {} - -local application = require "hs.application" -local window = require "hs.window" -local screen = require "hs.screen" -local fnutils = require "hs.fnutils" -local geometry = require "hs.geometry" -local alert = require "hs.alert" -local layouts = require "hs.tiling.layouts" -local spaces = {} -local settings = { layouts = {} } - -local excluded = {} --- navigate to layout by name -function tiling.goToLayout(name) - local space = getSpace() - local i = 0 - while space.layout ~= name and i < #settings.layouts do - space.layout = space.layoutCycle() - i = i + 1 - end - if i < #settings.layouts then - alert.show(space.layout, 1) - apply(space.windows, space.layout) - else - alert.show('Layout ' .. name .. ' does not exist', 1) - end -end - -function tiling.toggleFloat(floatfn) - local win = window:focusedWindow() - local id = win:id() - excluded[id] = not excluded[id] - - if excluded[id] then - if floatfn then floatfn(win) end - alert.show("Excluding " .. win:title() .. " from tiles") - else - alert.show("Adding " .. win:title() .. " to tiles") - end - - local space = getSpace() - apply(space.windows, space.layout) -end - -function tiling.addLayout(name, layout) - layouts[name] = layout - setLayouts(layouts) -end - -function tiling.set(name, value) - settings[name] = value -end - -function tiling.retile() - local space = getSpace() - apply(space.windows, space.layout) -end - -function tiling.cycle(direction) - local space = getSpace() - local windows = space.windows - local win = window:focusedWindow() or windows[1] - local direction = direction or 1 - local currentIndex = fnutils.indexOf(windows, win) - local layout = space.layout - if not currentIndex then return end - nextIndex = currentIndex + direction - if nextIndex > #windows then - nextIndex = 1 - elseif nextIndex < 1 then - nextIndex = #windows - end - - windows[nextIndex]:focus() - apply(windows, layout) -end - -function tiling.cycleLayout() - local space = getSpace() - space.layout = space.layoutCycle() - alert.show(space.layout, 1) - apply(space.windows, space.layout) -end - -function tiling.promote() - local space = getSpace() - local windows = space.windows - local win = window:focusedWindow() or windows[1] - local i = fnutils.indexOf(windows, win) - if not i then return end - - local current = table.remove(windows, i) - table.insert(windows, 1, current) - win:focus() - apply(windows, space.layout) -end - -function tiling.setMainVertical(val) - if val > 0 and val < 1 then - local space = getSpace() - if space.layout == 'main-vertical-variable' then - space.mainVertical = val - tiling.retile() - end - end -end - -function tiling.adjustMainVertical(factor) - local space = getSpace() - if space.layout == 'main-vertical-variable' then - local mainVertical = space.mainVertical - if mainVertical == nil then - mainVertical = 0.5 - end - tiling.setMainVertical(mainVertical + factor) - end -end - -function apply(windows, layout) - layouts[layout](windows) -end - -function isWindowIncluded(win) - onScreen = win:screen() == screen.mainScreen() - standard = win:isStandard() - hasTitle = #win:title() > 0 - isTiling = not excluded[win:id()] - return onScreen and standard and hasTitle and isTiling -end - --- Infer a 'space' from our existing spaces -function getSpace() - local windows = fnutils.filter(window.visibleWindows(), isWindowIncluded) - - fnutils.each(spaces, function(space) - local matches = 0 - fnutils.each(space.windows, function(win) - if fnutils.contains(windows, win) then matches = matches + 1 end - end) - space.matches = matches - end) - - table.sort(spaces, function(a, b) - return a.matches > b.matches - end) - - local space = {} - - if #spaces == 0 or spaces[1].matches == 0 then - space.windows = windows - space.layoutCycle = fnutils.cycle(settings.layouts) - space.layout = settings.layouts[1] - table.insert(spaces, space) - else - space = spaces[1] - end - - space.windows = syncWindows(space.windows, windows) - return space -end - -function syncWindows(windows, newWindows) - -- Remove any windows no longer around - windows = fnutils.filter(windows, function(win) - return fnutils.contains(newWindows, win) - end) - - -- Add any new windows since - fnutils.each(newWindows, function(win) - if fnutils.contains(windows, win) == false then - table.insert(windows, win) - end - end) - - -- Remove any bad windows - windows = fnutils.filter(windows, function(win) - return win:isStandard() - end) - - return windows -end - -function setLayouts(layouts) - local n = 0 - for k, v in pairs(layouts) do - n = n + 1 - settings.layouts[n] = k - end -end - - -setLayouts(layouts) - -return tiling diff --git a/hammerspoon/hs/tiling/layouts.lua b/hammerspoon/hs/tiling/layouts.lua deleted file mode 100755 index 5d9de0eb..00000000 --- a/hammerspoon/hs/tiling/layouts.lua +++ /dev/null @@ -1,200 +0,0 @@ -local fnutils = require "hs.fnutils" -local layouts = {} - -layouts['fullscreen'] = function(windows) - fnutils.each(windows, function(window) - window:maximize() - end) -end - -layouts['main-vertical'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - if index == 1 then - frame.w = frame.w / 2 - else - frame.x = frame.x + frame.w / 2 - frame.w = frame.w / 2 - frame.h = frame.h / (winCount - 1) - frame.y = frame.y + frame.h * (index - 2) - end - - win:setFrame(frame) - end -end - -layouts['main-horizontal'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - if index == 1 then - frame.h = frame.h / 2 - else - frame.y = frame.y + frame.h / 2 - frame.h = frame.h / 2 - frame.w = frame.w / (winCount - 1) - frame.x = frame.x + frame.w * (index - 2) - end - - win:setFrame(frame) - end -end - -layouts['columns'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - frame.w = frame.w / winCount - frame.x = frame.x + (index - 1) * frame.w - frame.y = 0 - - win:setFrame(frame) - end -end - -layouts['rows'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - frame.h = frame.h / winCount - frame.y = frame.y + (index - 1) * frame.h - frame.x = 0 - - win:setFrame(frame) - end -end - -layouts['gp-vertical'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - local width - local height - local x = 0 - local y = 0 - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - if index == 1 then - height = frame.h - width = frame.w / 2 - elseif index % 2 == 0 then - if index ~= winCount then - height = height / 2 - end - x = x + width - else - if index ~= winCount then - width = width / 2 - end - y = y + height - end - - frame.x = frame.x + x - frame.y = frame.y + y - frame.w = width - frame.h = height - - win:setFrame(frame) - end -end - -layouts['gp-horizontal'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - local width - local height - local x = 0 - local y = 0 - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - if index == 1 then - height = frame.h / 2 - width = frame.w - elseif index % 2 == 0 then - if index ~= winCount then - width = width / 2 - end - y = y + height - else - if index ~= winCount then - height = height / 2 - end - x = x + width - end - - frame.x = frame.x + x - frame.y = frame.y + y - frame.w = width - frame.h = height - - win:setFrame(frame) - end -end - -layouts['main-vertical-variable'] = function(windows) - local winCount = #windows - - if winCount == 1 then - return layouts['fullscreen'](windows) - end - - local space = getSpace() - local mainVertical = space.mainVertical - - if mainVertical == nil then - mainVertical = 0.5 - end - - for index, win in pairs(windows) do - local frame = win:screen():frame() - - if index == 1 then - frame.w = frame.w * mainVertical - else - frame.x = frame.x + frame.w * mainVertical - frame.w = frame.w * (1 - mainVertical) - frame.h = frame.h / (winCount - 1) - frame.y = frame.y + frame.h * (index - 2) - end - - win:setFrame(frame) - end -end - -return layouts diff --git a/hammerspoon/init.lua b/hammerspoon/init.lua index fa7077f6..94a97e5b 100644 --- a/hammerspoon/init.lua +++ b/hammerspoon/init.lua @@ -1,71 +1,108 @@ -local tiling = require 'hs.tiling' -local vimouse = require('vimouse') -local appliaction = require 'hs.application' +local vimouse = require 'vimouse' +local app = require 'hs.application' +local eventtap = require 'hs.eventtap' +local hotkey = require 'hs.hotkey' +local layout = require 'hs.layout' +local win = require 'hs.window' + local hyper = { 'cmd', 'alt', 'shift', 'ctrl' } +local laptopMonitor = "Built-in Retina Display" +local mainMonitor = "TODO TODO" --- Window management --------------------- +-- Define position values that don't exist by default in hs.layout.* +local positions = { + rightTop = { x=0.5, y=0, w=0.5, h=0.5 }, + rightBottom = { x=0.5, y=0.5, w=0.5, h=0.5 } +} -hs.window.animationDuration = 0 -tiling.set('layouts', { 'fullscreen', 'gp-vertical' }) +local layoutDouble = { + {"Reminders", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Calendar", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Firefox", nil, mainMonitor, layout.left50, nil, nil}, + {"ForkLift", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Spotify", nil, laptopMonitor, layout.maximized, nil, nil}, + {"iTerm", nil, mainMonitor, layout.right50, nil, nil}, + {"Messages", nil, mainMonitor, positions.rightTop, nil, nil}, + {"Signal", nil, mainMonitor, positions.rightBottom, nil, nil}, + {"Telegram", nil, mainMonitor, positions.rightTop, nil, nil}, + {"Microsoft Teams", nil, mainMonitor, positions.rightBottom, nil, nil}, +} -function isInScreen(screen, win) - return win:screen() == screen -end +local layoutSingle = { + {"Reminders", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Calendar", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Firefox", nil, laptopMonitor, layout.maximized, nil, nil}, + {"ForkLift", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Spotify", nil, laptopMonitor, layout.maximized, nil, nil}, + {"iTerm", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Messages", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Signal", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Telegram", nil, laptopMonitor, layout.maximized, nil, nil}, + {"Microsoft Teams", nil, laptopMonitor, layout.maximized, nil, nil}, +} -function moveMouse() - local pt = hs.geometry.rectMidPoint(hs.window.focusedWindow():frame()) - hs.mouse.setAbsolutePosition(pt) -end +local appNames = { + "Reminders", + "Calendar", + "Firefox", + "ForkLift", + "Spotify", + "iTerm", + "Messages", + "Signal", + "Telegram", + "Microsoft Teams", +} -function focusScreen(screen) - -- Get windows within screen, ordered from front to back. - -- If no windows exist, bring focus to desktop. Otherwise, set focus on - -- front-most application window. - local windows = hs.fnutils.filter( - hs.window.orderedWindows(), - hs.fnutils.partial(isInScreen, screen)) - local windowToFocus = #windows > 0 and windows[1] or hs.window.desktop() - windowToFocus:focus() - moveMouse() +local function launchApps() + for i, appName in ipairs(appNames) do + app.launchOrFocus(appName) + end end -local function fullsize(window) - frame = window:screen():frame() - frame.x = 0 - frame.y = 0 - frame.w = frame.w - frame.h = frame.h - window:setFrame(frame) +local function moveMouse() + local pt = hs.geometry.rectMidPoint(win.focusedWindow():frame()) + hs.mouse.absolutePosition(pt) end +-- Window management +-------------------- + +win.animationDuration = 0 + -- Move and click mouse via keyboard vimouse(hyper, 'm') -hs.hotkey.bind(hyper, 'f', function() tiling.toggleFloat(fullsize); moveMouse() end) -hs.hotkey.bind(hyper, 'r', function() tiling.retile(); moveMouse() end) -hs.hotkey.bind(hyper, 'a', function() tiling.cycle(1); moveMouse() end) -hs.hotkey.bind(hyper, 'w', function() tiling.promote(); moveMouse() end) -hs.hotkey.bind(hyper, 'c', function() tiling.cycleLayout(); moveMouse() end) -hs.hotkey.bind(hyper, '[', function() hs.window.focusedWindow():moveOneScreenNorth(); moveMouse() end) -hs.hotkey.bind(hyper, ']', function() hs.window.focusedWindow():moveOneScreenSouth(); moveMouse() end) -hs.hotkey.bind(hyper, 'h', function() hs.window.focusedWindow():focusWindowWest(); moveMouse() end) -hs.hotkey.bind(hyper, 'j', function() hs.window.focusedWindow():focusWindowSouth(); moveMouse() end) -hs.hotkey.bind(hyper, 'k', function() hs.window.focusedWindow():focusWindowNorth(); moveMouse() end) -hs.hotkey.bind(hyper, 'l', function() hs.window.focusedWindow():focusWindowEast(); moveMouse() end) +-- Window Navigation +-- hotkey D is set in Dash itself +hotkey.bind(hyper, 'a', function() app.launchOrFocus('iTerm') end) +hotkey.bind(hyper, 's', function() app.launchOrFocus('Firefox') end) +hotkey.bind(hyper, 'f', function() app.launchOrFocus('ForkLift') end) +hotkey.bind(hyper, 'g', function() launchApps() end) +hotkey.bind(hyper, 'n', function() layout.apply(layoutSingle) end) +hotkey.bind(hyper, 'p', function() layout.apply(layoutDouble) end) + +-- Moving window around / navigating windows +hotkey.bind(hyper, 'z', function() win.focusedWindow():toggleFullScreen(); moveMouse() end) +hotkey.bind(hyper, '[', function() win.focusedWindow():moveOneScreenNorth(); moveMouse() end) +hotkey.bind(hyper, ']', function() win.focusedWindow():moveOneScreenSouth(); moveMouse() end) +hotkey.bind(hyper, 'h', function() win.focusedWindow():focusWindowWest(); moveMouse() end) +hotkey.bind(hyper, 'j', function() win.focusedWindow():focusWindowSouth(); moveMouse() end) +hotkey.bind(hyper, 'k', function() win.focusedWindow():focusWindowNorth(); moveMouse() end) +hotkey.bind(hyper, 'l', function() win.focusedWindow():focusWindowEast(); moveMouse() end) -- map hyper + number to the corresponding fn-key, since the touchbar -- kinda sucks, and karabiner-elements is breaking fn-function to show keys -hs.hotkey.bind(hyper, '1', function() hs.eventtap.keyStroke({}, 'F1') end) -hs.hotkey.bind(hyper, '2', function() hs.eventtap.keyStroke({}, 'F2') end) -hs.hotkey.bind(hyper, '3', function() hs.eventtap.keyStroke({}, 'F3') end) -hs.hotkey.bind(hyper, '4', function() hs.eventtap.keyStroke({}, 'F4') end) -hs.hotkey.bind(hyper, '5', function() hs.eventtap.keyStroke({}, 'F5') end) -hs.hotkey.bind(hyper, '6', function() hs.eventtap.keyStroke({}, 'F6') end) -hs.hotkey.bind(hyper, '7', function() hs.eventtap.keyStroke({}, 'F7') end) -hs.hotkey.bind(hyper, '8', function() hs.eventtap.keyStroke({}, 'F8') end) -hs.hotkey.bind(hyper, '9', function() hs.eventtap.keyStroke({}, 'F9') end) -hs.hotkey.bind(hyper, '0', function() hs.eventtap.keyStroke({}, 'F10') end) -hs.hotkey.bind(hyper, '-', function() hs.eventtap.keyStroke({}, 'F11') end) -hs.hotkey.bind(hyper, '=', function() hs.eventtap.keyStroke({}, 'F12') end) +hotkey.bind(hyper, '1', function() eventtap.keyStroke({}, 'F1') end) +hotkey.bind(hyper, '2', function() eventtap.keyStroke({}, 'F2') end) +hotkey.bind(hyper, '3', function() eventtap.keyStroke({}, 'F3') end) +hotkey.bind(hyper, '4', function() eventtap.keyStroke({}, 'F4') end) +hotkey.bind(hyper, '5', function() eventtap.keyStroke({}, 'F5') end) +hotkey.bind(hyper, '6', function() eventtap.keyStroke({}, 'F6') end) +hotkey.bind(hyper, '7', function() eventtap.keyStroke({}, 'F7') end) +hotkey.bind(hyper, '8', function() eventtap.keyStroke({}, 'F8') end) +hotkey.bind(hyper, '9', function() eventtap.keyStroke({}, 'F9') end) +hotkey.bind(hyper, '0', function() eventtap.keyStroke({}, 'F10') end) +hotkey.bind(hyper, '-', function() eventtap.keyStroke({}, 'F11') end) +hotkey.bind(hyper, '=', function() eventtap.keyStroke({}, 'F12') end)