nix/config/home/.hammerspoon/keyboard/yabai.lua

193 lines
8.3 KiB
Lua

local keymap = require 'keyboard.keymaps'
local yabai_cmd = '/etc/profiles/per-user/rayandrew/bin/yabai'
local jq_cmd = '/etc/profiles/per-user/rayandrew/bin/jq'
local function yabai_query(query, jq_filter)
local cmd = yabai_cmd .. ' -m query ' .. query
if jq_filter then cmd = cmd .. ' | ' .. jq_cmd .. ' ' .. jq_filter end
local handle = io.popen(cmd)
local result = handle:read('*a'):gsub('%s+', '')
handle:close()
return result
end
local function yabai(commands, logic)
local cmd_string = ''
for i, cmd in ipairs(commands) do
if i == 1 then
cmd_string = yabai_cmd .. ' -m ' .. cmd
else
if logic == 'and' then
cmd_string = cmd_string .. ' && ' .. yabai_cmd .. ' -m ' .. cmd
elseif logic == 'or' then
cmd_string = cmd_string .. ' || ' .. yabai_cmd .. ' -m ' .. cmd
else
cmd_string = cmd_string .. ' ; ' .. yabai_cmd .. ' -m ' .. cmd
end
end
end
os.execute(cmd_string)
end
local function yabai_key(opts)
keymap.super {
key = opts.key,
mods = opts.mods,
message = opts.message,
fn = function() yabai(opts.commands, opts.logic) end,
}
end
keymap.super {
key = 'return',
-- message = "Spawn Ghostty",
fn = function()
-- hs.application.launchOrFocus("Ghostty")
-- hs.timer.doAfter(0.1, function()
-- hs.eventtap.keyStroke({ "cmd" }, "n")
-- end)
os.execute 'open -na Ghostty'
end,
}
yabai_key { key = 'f', commands = { 'window --toggle zoom-fullscreen' } }
yabai_key { key = 'l', commands = { 'space --focus recent' } }
yabai_key { key = 'm', commands = { 'space --toggle mission-control' } }
yabai_key { key = 'p', commands = { 'window --toggle pip' } }
yabai_key { key = 'g', commands = { 'space --toggle padding', 'space --toggle gap' } }
yabai_key { key = 'r', commands = { 'space --rotate 90' } }
yabai_key { key = 't', commands = { 'window --toggle float', 'window --grid 4:4:1:1:2:2' } }
yabai_key { key = "'", commands = { 'space --layout stack' } }
yabai_key { key = ';', commands = { 'space --layout bsp' } }
yabai_key { key = 'tab', commands = { 'space --focus recent' } }
-- navigation
yabai_key { key = 'h', commands = { 'window --focus west', 'display --focus west' }, logic = 'or' }
yabai_key { key = 'j', commands = { 'window --focus south', 'display --focus south' }, logic = 'or' }
yabai_key { key = 'k', commands = { 'window --focus north', 'display --focus north' }, logic = 'or' }
yabai_key { key = 'l', commands = { 'window --focus east', 'display --focus east' }, logic = 'or' }
-- move windows (swap within space, or move to adjacent display if at edge)
yabai_key { mods = { 'shift' }, key = 'h', commands = { 'window --swap west', 'window --display west', 'display --focus west' }, logic = 'or' }
yabai_key { mods = { 'shift' }, key = 'j', commands = { 'window --swap south', 'window --display south', 'display --focus south' }, logic = 'or' }
yabai_key { mods = { 'shift' }, key = 'k', commands = { 'window --swap north', 'window --display north', 'display --focus north' }, logic = 'or' }
yabai_key { mods = { 'shift' }, key = 'l', commands = { 'window --swap east', 'window --display east', 'display --focus east' }, logic = 'or' }
-- spaces - focus space and its display
local function focus_space(space_num)
local display = yabai_query('--spaces', "'.[] | select(.index == " .. space_num .. ") | .display'")
if display and display ~= '' then
os.execute(yabai_cmd .. ' -m display --focus ' .. display)
hs.timer.usleep(50000) -- 50ms delay
end
os.execute(yabai_cmd .. ' -m space --focus ' .. space_num)
end
keymap.super { key = '1', fn = function() focus_space(1) end }
keymap.super { key = '2', fn = function() focus_space(2) end }
keymap.super { key = '3', fn = function() focus_space(3) end }
keymap.super { key = '4', fn = function() focus_space(4) end }
keymap.super { key = '5', fn = function() focus_space(5) end }
keymap.super { key = '6', fn = function() focus_space(6) end }
keymap.super { key = '7', fn = function() focus_space(7) end }
keymap.super { key = '8', fn = function() focus_space(8) end }
keymap.super { key = '9', fn = function() focus_space(9) end }
keymap.super { key = '0', fn = function() focus_space(10) end }
-- move window to space and follow
yabai_key { mods = { 'shift' }, key = '1', commands = { 'window --space 1', 'space --focus 1' } }
yabai_key { mods = { 'shift' }, key = '2', commands = { 'window --space 2', 'space --focus 2' } }
yabai_key { mods = { 'shift' }, key = '3', commands = { 'window --space 3', 'space --focus 3' } }
yabai_key { mods = { 'shift' }, key = '4', commands = { 'window --space 4', 'space --focus 4' } }
yabai_key { mods = { 'shift' }, key = '5', commands = { 'window --space 5', 'space --focus 5' } }
yabai_key { mods = { 'shift' }, key = '6', commands = { 'window --space 6', 'space --focus 6' } }
yabai_key { mods = { 'shift' }, key = '7', commands = { 'window --space 7', 'space --focus 7' } }
yabai_key { mods = { 'shift' }, key = '8', commands = { 'window --space 8', 'space --focus 8' } }
yabai_key { mods = { 'shift' }, key = '9', commands = { 'window --space 9', 'space --focus 9' } }
yabai_key { mods = { 'shift' }, key = '0', commands = { 'window --space 10', 'space --focus 10' } }
-- move current space between displays
yabai_key { mods = { 'ctrl' }, key = 'h', message = 'Move space to left display', commands = { 'space --display west' } }
yabai_key { mods = { 'ctrl' }, key = 'l', message = 'Move space to right display', commands = { 'space --display east' } }
-- create new space and move window to it
keymap.super {
key = 'n',
mods = { 'shift' },
message = 'Create new space and move window',
fn = function()
os.execute(yabai_cmd .. ' -m space --create')
hs.timer.usleep(100000) -- 100ms
local index = yabai_query('--spaces --display', '\'map(select(."is-native-fullscreen" == false))[-1].index\'')
if index and index ~= '' then
os.execute(yabai_cmd .. ' -m window --space ' .. index)
os.execute(yabai_cmd .. ' -m space --focus ' .. index)
end
end,
}
-- split type - use insert direction to control next window placement
-- yabai_key { key = 'v', commands = { 'window --insert east' } }
-- yabai_key { mods = { 'shift' }, key = 'v', commands = { 'window --insert south' } }
yabai_key { key = 'v', commands = { 'config split_type vertical' } }
yabai_key { mods = { 'shift' }, key = 'v', commands = { 'config split_type horizontal' } }
-- Resize mode
local resize_mode = hs.hotkey.modal.new()
-- Function to show resize mode indicator
function resize_mode:entered() hs.alert.show('Resize Mode', { textSize = 20, radius = 10 }, 999999) end
function resize_mode:exited() hs.alert.closeAll() end
-- Enter resize mode
keymap.super {
key = 'r',
message = 'Enter resize mode',
fn = function() resize_mode:enter() end,
}
-- Exit resize mode (escape or return)
resize_mode:bind({}, 'escape', function() resize_mode:exit() end)
resize_mode:bind({}, 'return', function() resize_mode:exit() end)
-- Resize bindings (no modifiers needed in resize mode)
resize_mode:bind({}, 'h', function() os.execute(yabai_cmd .. ' -m window --resize left:-20:0 || ' .. yabai_cmd .. ' -m window --resize right:-20:0') end)
resize_mode:bind({}, 'j', function() os.execute(yabai_cmd .. ' -m window --resize bottom:0:20 || ' .. yabai_cmd .. ' -m window --resize top:0:20') end)
resize_mode:bind({}, 'k', function() os.execute(yabai_cmd .. ' -m window --resize top:0:-20 || ' .. yabai_cmd .. ' -m window --resize bottom:0:-20') end)
resize_mode:bind({}, 'l', function() os.execute(yabai_cmd .. ' -m window --resize right:20:0 || ' .. yabai_cmd .. ' -m window --resize left:20:0') end)
-- Shift variants for larger increments
resize_mode:bind(
{ 'shift' },
'h',
function() os.execute(yabai_cmd .. ' -m window --resize left:-50:0 || ' .. yabai_cmd .. ' -m window --resize right:-50:0') end
)
resize_mode:bind({ 'shift' }, 'j', function() os.execute(yabai_cmd .. ' -m window --resize bottom:0:50 || ' .. yabai_cmd .. ' -m window --resize top:0:50') end)
resize_mode:bind(
{ 'shift' },
'k',
function() os.execute(yabai_cmd .. ' -m window --resize top:0:-50 || ' .. yabai_cmd .. ' -m window --resize bottom:0:-50') end
)
resize_mode:bind({ 'shift' }, 'l', function() os.execute(yabai_cmd .. ' -m window --resize right:50:0 || ' .. yabai_cmd .. ' -m window --resize left:50:0') end)
-- Equalize windows
resize_mode:bind({}, 'e', function()
os.execute(yabai_cmd .. ' -m space --balance')
resize_mode:exit()
end)