diff --git a/home/ags/files/config.js b/home/ags/files/config.js index d2341ae..ef6cc64 100644 --- a/home/ags/files/config.js +++ b/home/ags/files/config.js @@ -4,6 +4,7 @@ const mpris = await Service.import("mpris") const audio = await Service.import("audio") const battery = await Service.import("battery") const systemtray = await Service.import("systemtray") +import { getIconName } from "./utils.js" const date = Variable("", { poll: [1000, 'date "+%H:%M:%S %b %e."'], @@ -11,14 +12,21 @@ const date = Variable("", { function Clients() { const activeId = hyprland.active.client.bind("address") - const clients = hyprland.bind("clients") - .as(cl => { - return cl.filter(c => c.workspace.id === hyprland.active.workspace.id).map(({ address, title }) => Widget.Button({ - child: Widget.Label(`${title}`), - class_name: activeId.as(i => `${i === address ? "focused" : ""}`), + let clients = hyprland.clients.filter(a => a.workspace.id == hyprland.active.workspace.id).map(({ address, title }) => + Widget.Button({ + child: Widget.Box({ + children: [ + Widget.Icon({ + vexpand: false, + size: 16, + className: "app-icon", + icon: getIconName(hyprland.clients.find(c => c.address === address)) + }), + Widget.Label(`${title}`) + ], + }), + class_name: activeId.as(i => `${i === address ? "client-title focused" : "client-title"}`), })) - }) - return Widget.Box({ class_name: "clients", children: clients, @@ -27,29 +35,27 @@ function Clients() { function Workspaces() { const activeId = hyprland.active.workspace.bind("id") - const workspaces = hyprland.bind("workspaces") - .as(ws => { + const workspaces = hyprland.bind("workspaces").as(ws => { ws.sort((a, b) => a.id - b.id) - return ws.map(({ id }) => Widget.Button({ - on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), - child: Widget.Label(`${id}`), - class_name: activeId.as(i => `${i === id ? "focused" : ""}`), - })) + return ws.map(({ id, monitorID }) => + Widget.Button({ + attribute: monitorID, + label: `${id}`, + onClicked: () => dispatch(i), + class_name: activeId.as(i => `${i === id ? "focused" : ""}`), + }) + ) }) return Widget.Box({ - class_name: "workspaces", children: workspaces, + setup: self => self.hook(hyprland, () => self.children.forEach(btn => { + btn.visible = hyprland.active.monitor.id === btn.attribute + })), }) } -// function ClientTitle() { -// return Widget.Label({ -// class_name: "client-title", -// label: hyprland.active.client.bind("title"), -// }) -// } function Clock() { diff --git a/home/ags/files/style.css b/home/ags/files/style.css index 06c1c73..9f70da2 100644 --- a/home/ags/files/style.css +++ b/home/ags/files/style.css @@ -6,11 +6,19 @@ label { font-weight: bold; } +.client-title { + padding-left: 0.7em; + padding-right: 0.7em; + margin-right: 0.3em; +} + .client-title, .clock { background: #1f2430; border-radius: 0.3em; - padding-left: 0.7em; - padding-right: 0.7em; +} + +.app-icon { + margin-right: 0.6em; } button { diff --git a/home/ags/files/utils.js b/home/ags/files/utils.js new file mode 100644 index 0000000..5247fd6 --- /dev/null +++ b/home/ags/files/utils.js @@ -0,0 +1,72 @@ +import { Applications } from "resource:///com/github/Aylur/ags/service/applications.js"; + +const app_icons = new Applications().list.reduce( + (acc, app) => { + if (app.icon_name) { + acc.classOrNames[app.wm_class ?? app.name] = app.icon_name; + acc.executables[app.executable] = app.icon_name; + } + return acc; + }, + { classOrNames: {}, executables: {} }, +); + +export function getIconName(client) { + if (!client) { + return "missing"; + } + + let icon = app_icons.classOrNames[client.class]; + + if (!icon) { + // TODO cache? + const filePath = `${App.configDir}/assets/${client.class}.png`; + if (fileExists(filePath)) { + icon = filePath; + app_icons.classOrNames[client.class] = icon; + } + } + + if (!icon) { + // TODO cache? + const filePath = `${App.configDir}/assets/${client.class}.svg`; + if (fileExists(filePath)) { + icon = filePath; + app_icons.classOrNames[client.class] = icon; + } + } + + if (!icon) { + const binaryName = Utils.exec(`ps -p ${client.pid} -o comm=`); + icon = app_icons.executables[binaryName]; + if (!icon) { + let key = Object.keys(app_icons.executables).find((key) => key.startsWith(binaryName)); + if (key) { + icon = app_icons.executables[key]; + } + } + if (icon) { + app_icons[client.class] = icon; + } + } + + if (!icon) { + const icon_key = Object.keys(app_icons.classOrNames).find( + (key) => + key.includes(client.title) || + key.includes(client.initialTitle) || + key.includes(client.initialClass) || + key.includes(client.class), + ); + if (icon_key) { + icon = app_icons.classOrNames[icon_key]; + app_icons.classOrNames[client.class] = icon; + } + } + + if (!icon) { + app_icons.classOrNames[client.class] = "missing"; + } + + return icon; +} diff --git a/home/nvim/default.nix b/home/nvim/default.nix index 58613ac..308134b 100644 --- a/home/nvim/default.nix +++ b/home/nvim/default.nix @@ -24,10 +24,10 @@ libclang cmake-language-server vscode-langservers-extracted - typescript yaml-language-server bash-language-server nodePackages.vue-language-server + nodePackages.typescript-language-server docker-compose-language-service dockerfile-language-server-nodejs vim-language-server @@ -35,8 +35,7 @@ rust-analyzer gopls jdt-language-server - # emmet-ls - emmet-language-server + emmet-ls ruff-lsp csharp-ls typst-lsp