Skip to content

Workspace not updating from aerospace when workspace is empty. #754

@Vib1240n

Description

@Vib1240n

Not sure if this is a Macos 26 issue or just issue in my code. I have sketchybar along with Aerospace. I can get all the active workspaces showing up, along side with the space name app icons, but every time I close an app in a workspace and leave it, which makes the workspace empty it should update sketchybar and remove that workspace but it stays persistent. It only goes away with a sketchybar --reload.

Here's my code for spaces-aerospace.lua

local colors = require("colors")
local icons = require("icons")
local settings = require("settings")
local app_icons = require("helpers.app_icons")

-- local LIST_ALL = "aerospace list-workspaces --all"
local LIST_CURRENT = "aerospace list-workspaces --focused"
local LIST_MONITORS = "aerospace list-monitors | awk '{print $1}'"
local LIST_WORKSPACES = "aerospace list-workspaces --monitor all --empty no"
local LIST_APPS = "aerospace list-windows --workspace %s | awk -F'|' '{gsub(/^ *| *$/, \"\", $2); print $2}'"
local spaces = {}
local function getIconForApp(appName)
	return app_icons[appName] or "?"
end

local function updateSpaceIcons(spaceId, workspaceName)
	local icon_strip = ""
	local shouldDraw = false

	sbar.exec(LIST_APPS:format(workspaceName), function(appsOutput)
		-- local appsOutput = execCommand(LIST_APPS:format(workspaceName))
		if not appsOutput then
			print("Warning: Failed to execute command for workspace: " .. workspaceName)
			return
		end
		local appFound = false

		for app in appsOutput:gmatch("[^\r\n]+") do
			local appName = app:match("^%s*(.-)%s*$") -- Trim whitespace
			if appName and appName ~= "" then
				icon_strip = icon_strip .. " " .. getIconForApp(appName)
				appFound = true
				shouldDraw = true
			end
		end

		if not appFound then
			icon_strip = " - "
			shouldDraw = true
		end

		if spaces[spaceId] then
			spaces[spaceId].item:set({
				label = { string = icon_strip, drawing = shouldDraw },
			})
		else
			print("Warning: Space ID '" .. spaceId .. "' not found when updating icons.")
		end
	end)
end

local function addWorkspaceItem(workspaceName, monitorId, isSelected)
	local spaceId = "workspace_" .. workspaceName

	if not spaces[spaceId] then
		local space_item = sbar.add("item", spaceId, {
			icon = {
				font = { family = settings.font.numbers },
				string = workspaceName,
				highlight_color = colors.teal,
			},
			label = {
				highlight_color = colors.teal,
				font = "sketchybar-app-font:Regular:16.0",
				y_offset = -2,
			},
			blur_radius = 30,
			background = {
				padding_right = settings.paddings - 5,
				padding_left = settings.paddings - 5,
			},
			popup = {
				background = {
					border_width = 0,
					border_color = colors.black,
				},
				drawing = false,
			},
			click_script = "aerospace workspace " .. workspaceName,
			display = monitorId,
		})

		-- Create bracket for double border effect
		local space_bracket = sbar.add("bracket", { spaceId }, {
			background = {
				-- color = colors.with_alpha(colors.bar.bg, 0.5),
				-- border_color = colors.white,
				-- height = 28,
				-- border_width = 2,
			},
			drawing = false,
		})

		-- Subscribe to mouse events for changing workspace
		space_item:subscribe("mouse.clicked", function()
			sbar.exec("aerospace workspace " .. workspaceName)
		end)

		-- Store both the item and its bracket in the spaces table
		spaces[spaceId] = { item = space_item, bracket = space_bracket }
	end

	spaces[spaceId].item:set({
		icon = { highlight = isSelected },
		label = { highlight = isSelected },
	})

	spaces[spaceId].bracket:set({
		-- background = { border_color = isSelected and colors.dirty_white or colors.transparent },
		background = {
			color = colors.transparent,
			border_color = colors.bg2,
			height = 28,
			border_width = 0,
		},
	})

	updateSpaceIcons(spaceId, workspaceName)
end

local function drawSpaces()
		sbar.exec(LIST_MONITORS, function(monitorsOutput)
			-- Cache the focused workspace to avoid multiple `LIST_CURRENT` queries
			sbar.exec(LIST_CURRENT, function(focusedWorkspaceOutput)
				local focusedWorkspace = focusedWorkspaceOutput:match("[^\r\n]+")

				-- Iterate through monitors and workspaces
				for monitorId in monitorsOutput:gmatch("[^\r\n]+") do
					sbar.exec(LIST_WORKSPACES:format(monitorId), function(workspacesOutput)
						for workspaceName in workspacesOutput:gmatch("[^\r\n]+") do
							local isSelected = workspaceName == focusedWorkspace
							addWorkspaceItem(workspaceName, monitorId, isSelected)
						end
					end)
				end
			end)
		end)
end

drawSpaces()

local space_window_observer = sbar.add("item", {
	drawing = false,
	updates = true,
})

local spaces_indicator = sbar.add("item", {
	padding_left = settings.paddings - 7,
	padding_right = settings.paddings - 10,
	icon = {
		string = icons.switch.on,
		padding_left = settings.paddings - 2,
		padding_right = settings.paddings - 1,
		color = colors.black,
	},
	label = {
		string = "Spaces",
		width = 0,
		padding_left = settings.paddings - 10,
		padding_right = settings.paddings - 2,
		color = colors.bar.bg,
	},
	background = {
		color = colors.transparent,
		border_color = colors.bar.bg,
	},
})

space_window_observer:subscribe("aerospace_workspace_change", function(env)
	drawSpaces()
end)

space_window_observer:subscribe("front_app_switched", function()
	drawSpaces()
end)

space_window_observer:subscribe("space_windows_change", function()
	drawSpaces()
end)

spaces_indicator:subscribe("swap_menus_and_spaces", function(env)
	local currently_on = spaces_indicator:query().icon.value == icons.switch.on
	spaces_indicator:set({
		icon = currently_on and icons.switch.off or icons.switch.on,
	})
	drawSpaces()
end)

spaces_indicator:subscribe("mouse.entered", function(env)
	sbar.animate("tanh", 30, function()
		spaces_indicator:set({
			background = {
				color = colors.bar.bg,
				border_color = { alpha = 1.0 },
			},
			icon = { color = colors.bar.icon_light },
			label = { width = "dynamic", string = "Menu", color = colors.bar.label_light },
		})
		drawSpaces()
	end)
end)

spaces_indicator:subscribe("mouse.exited", function(env)
	sbar.animate("tanh", 30, function()
		spaces_indicator:set({
			background = {
				color = { alpha = 0.0 },
				border_color = { alpha = 0.0 },
			},
			icon = { color = colors.black },
			label = { width = 0 },
		})

		drawSpaces()
	end)
end)

spaces_indicator:subscribe("mouse.clicked", function(env)
	sbar.trigger("swap_menus_and_spaces")
	drawSpaces()
end)

Majority of the code for this file is from some repo that I can't find now along with the default lua config that's provided. I've tried to debug that code myself and can't really see what's wrong that it's not removing the inactive workspace correctly. So I'm not sure if this is a macos issue or a sketchybar issue or if my code is just wrong.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions