nix/config/sketchybar/items/spaces.lua

180 lines
6 KiB
Lua

local constants = require 'constants'
local settings = require 'config.settings'
local utils = require 'utils'
local spaces = {}
local paddings = {}
local focusedWorkspace = nil
local swapWatcher = sbar.add('item', {
drawing = false,
updates = true,
})
local currentWorkspaceWatcher = sbar.add('item', {
drawing = false,
updates = true,
})
-- Modify this file with Visual Studio Code - at least vim does have problems with the icons
-- copy "Icons" from the nerd fonts cheat sheet and replace icon and name accordingly below
-- https://www.nerdfonts.com/cheat-sheet
local spaceConfigs <const> = {
['1'] = { icon = '󱞁', name = 'Main' },
['2'] = { icon = '󰘦 ', name = 'Dev' },
['3'] = { icon = '󰧑', name = 'AI' },
['4'] = { icon = '', name = '' },
['5'] = { icon = '󰌾', name = 'Misc' },
['6'] = { icon = '󱉟', name = 'Library' },
['7'] = { icon = '󰎆', name = 'Music' },
['8'] = { icon = '󰇮', name = 'Mail' },
['9'] = { icon = '󰭹', name = 'Chat' },
['10'] = { icon = '󰖟', name = 'Browser' },
['t'] = { icon = '', name = 'Meeting' },
}
-- Track which workspaces have windows
local workspaceHasWindows = {}
local updateWorkspaceVisibility = utils.coro.async(function()
local output = utils.coro.await(utils.coro.exec(constants.aerospace_cmd .. " list-windows --all --format '%{workspace}'"))
-- Reset all
for ws, _ in pairs(workspaceHasWindows) do
workspaceHasWindows[ws] = false
end
-- Mark workspaces that have windows
if output then
for ws in output:gmatch '[^\r\n]+' do
workspaceHasWindows[ws] = true
end
end
-- Update visibility for each space
for workspaceName, _ in pairs(spaceConfigs) do
local spaceName = constants.items.SPACES .. '.' .. workspaceName
local space = spaces[spaceName]
local padding = paddings[spaceName]
if space then
local hasWindows = workspaceHasWindows[workspaceName] == true
local isFocused = focusedWorkspace == workspaceName
local shouldShow = hasWindows or isFocused
space:set { drawing = shouldShow }
if padding then padding:set { drawing = shouldShow } end
end
end
end)
local function selectCurrentWorkspace(focusedWorkspaceName)
focusedWorkspace = focusedWorkspaceName
for workspaceName, _ in pairs(spaceConfigs) do
local spaceName = constants.items.SPACES .. '.' .. workspaceName
local item = spaces[spaceName]
local padding = paddings[spaceName]
if item ~= nil then
local isSelected = workspaceName == focusedWorkspaceName
local hasWindows = workspaceHasWindows[workspaceName] == true
local shouldShow = hasWindows or isSelected
-- Show/hide based on windows or focus
item:set {
drawing = shouldShow,
icon = { color = isSelected and settings.colors.bg1 or settings.colors.white },
label = { color = isSelected and settings.colors.bg1 or settings.colors.white },
background = { color = isSelected and settings.colors.white or settings.colors.bg1 },
}
if padding then padding:set { drawing = shouldShow } end
end
end
updateWorkspaceVisibility()
sbar.trigger(constants.events.UPDATE_WINDOWS)
end
local findAndSelectCurrentWorkspace = utils.coro.async(function()
local focusedWorkspaceOutput = utils.coro.await(utils.coro.exec(constants.aerospace.GET_CURRENT_WORKSPACE))
if focusedWorkspaceOutput then
local focusedWorkspaceName = focusedWorkspaceOutput:match '[^\r\n]+'
selectCurrentWorkspace(focusedWorkspaceName)
end
end)
local function addWorkspaceItem(workspaceName)
local spaceName = constants.items.SPACES .. '.' .. workspaceName
local spaceConfig = spaceConfigs[workspaceName]
-- Skip workspaces without a config entry
if not spaceConfig then return end
local hasIcon = spaceConfig.icon and spaceConfig.icon ~= ''
local hasName = spaceConfig.name and spaceConfig.name ~= ''
local icon = hasIcon and spaceConfig.icon or workspaceName
local name = hasName and spaceConfig.name or workspaceName
local useBold = not hasIcon
local fontStyle = useBold and settings.fonts.styles.bold or settings.fonts.styles.regular
local iconFont = settings.fonts.text .. ':' .. fontStyle .. ':' .. settings.dimens.text.icon
spaces[spaceName] = sbar.add('item', spaceName, {
drawing = false, -- start hidden, will show if has windows or is focused
label = {
width = 0,
padding_left = 0,
string = name,
y_offset = 1,
},
icon = {
string = icon,
font = iconFont,
color = settings.colors.white,
y_offset = 1,
},
background = {
color = settings.colors.bg1,
},
click_script = constants.aerospace_cmd .. ' workspace ' .. workspaceName,
})
spaces[spaceName]:subscribe('mouse.entered', function(env)
sbar.animate('tanh', 30, function() spaces[spaceName]:set { label = { width = 'dynamic' } } end)
end)
spaces[spaceName]:subscribe('mouse.exited', function(env)
sbar.animate('tanh', 30, function() spaces[spaceName]:set { label = { width = 0 } } end)
end)
paddings[spaceName] = sbar.add('item', spaceName .. '.padding', {
drawing = false,
width = settings.dimens.padding.label,
})
end
local createWorkspaces = utils.coro.async(function()
local workspacesOutput = utils.coro.await(utils.coro.exec(constants.aerospace.LIST_ALL_WORKSPACES))
if workspacesOutput then
for workspaceName in workspacesOutput:gmatch '[^\r\n]+' do
addWorkspaceItem(workspaceName)
end
end
findAndSelectCurrentWorkspace()
end)
swapWatcher:subscribe(constants.events.SWAP_MENU_AND_SPACES, function(env)
local isShowingSpaces = env.isShowingMenu == 'off' and true or false
if isShowingSpaces then
updateWorkspaceVisibility()
else
sbar.set('/' .. constants.items.SPACES .. '\\..*/', { drawing = false })
end
end)
currentWorkspaceWatcher:subscribe(constants.events.AEROSPACE_WORKSPACE_CHANGED, function(env) selectCurrentWorkspace(env.FOCUSED_WORKSPACE) end)
-- Also update on window changes
currentWorkspaceWatcher:subscribe('front_app_switched', function(env) updateWorkspaceVisibility() end)
createWorkspaces()