This repository has no description
6.6 kB
208 lines
1{ self, ... }:
2{
3 flake.wrapperModules.workspace-manager =
4 {
5 config,
6 lib,
7 pkgs,
8 ...
9 }:
10 let
11 cfg = config.lass.workspace-manager;
12
13 workspaceType = lib.types.submodule {
14 options = {
15 directory = lib.mkOption {
16 type = lib.types.str;
17 description = "Directory to use for this workspace";
18 };
19 };
20 };
21
22 # Generate a directory with JSON files for each declared workspace
23 systemConfigDir = pkgs.linkFarm "workspace-manager-configs" (
24 lib.mapAttrsToList (name: ws: {
25 name = "${name}.json";
26 path = pkgs.writeText "${name}.json" (builtins.toJSON { inherit (ws) directory; });
27 }) cfg.workspaces
28 );
29 in
30 {
31 options.lass.workspace-manager = {
32 enable = lib.mkEnableOption "workspace manager daemon for sway";
33
34 package = lib.mkOption {
35 type = lib.types.package;
36 default = self.packages.${pkgs.system}.workspace-manager-daemon;
37 description = "The workspace-manager-daemon package to use";
38 };
39
40 workspaces = lib.mkOption {
41 type = lib.types.attrsOf workspaceType;
42 default = { };
43 description = "Declarative workspace configurations (take precedence over user configs)";
44 example = lib.literalExpression ''
45 {
46 dev = { directory = "/home/user/src/myproject"; };
47 music = { directory = "/home/user/Music"; };
48 }
49 '';
50 };
51
52 configDir = lib.mkOption {
53 type = lib.types.str;
54 default = "~/workspaces";
55 description = "Directory containing user workspace configuration files";
56 };
57
58 defaultDirectory = lib.mkOption {
59 type = lib.types.str;
60 default = "~";
61 description = "Default directory for workspaces without configuration";
62 };
63 };
64
65 config = lib.mkIf cfg.enable {
66 systemd.user.services.workspace-manager = {
67 description = "Workspace Manager Daemon";
68 partOf = [ "sway-session.target" ];
69 wantedBy = [ "sway-session.target" ];
70 serviceConfig = {
71 Type = "simple";
72 ExecStart = "${cfg.package}/bin/workspace-manager-daemon";
73 Restart = "on-failure";
74 RestartSec = 5;
75 Environment = [
76 "WORKSPACE_MANAGER_CONFIG_DIR=${cfg.configDir}"
77 "WORKSPACE_MANAGER_SYSTEM_CONFIG_DIR=${systemConfigDir}"
78 "WORKSPACE_MANAGER_DEFAULT_DIR=${cfg.defaultDirectory}"
79 ];
80 };
81 };
82 };
83 };
84
85 perSystem =
86 {
87 pkgs,
88 ...
89 }:
90 let
91 python = pkgs.python3;
92 in
93 {
94 packages.workspace-manager =
95 (pkgs.writeShellApplication {
96 name = "workspace-manager";
97 runtimeInputs = [
98 pkgs.socat
99 pkgs.jq
100 ];
101 text = builtins.readFile ./workspace-manager.sh;
102 }).overrideAttrs
103 { passthru.usage = builtins.readFile ./usage.kdl; };
104
105 packages.workspace-menu = pkgs.writeShellApplication {
106 name = "workspace-menu";
107 runtimeInputs = [
108 pkgs.sway
109 pkgs.jq
110 self.packages.${pkgs.system}.menu
111 pkgs.libnotify
112 pkgs.findutils
113 pkgs.gnused
114 pkgs.coreutils
115 pkgs.gnugrep
116 # The wrapped Dev Edition daemon, not upstream stable firefox —
117 # otherwise "Restore tabs" launches a separate browser/profile.
118 self.packages.${pkgs.system}.firefox
119 ];
120 text = builtins.readFile ./workspace-menu.sh;
121 };
122
123 packages.workspace-manager-daemon = pkgs.stdenv.mkDerivation {
124 pname = "workspace-manager-daemon";
125 version = "0.1.0";
126 src = ./.;
127 nativeBuildInputs = [
128 pkgs.makeWrapper
129 pkgs.ruff
130 python.pkgs.mypy
131 ];
132 doCheck = true;
133 checkPhase = ''
134 runHook preCheck
135 ruff check daemon.py
136 ruff format --check daemon.py
137 mypy --strict daemon.py
138 runHook postCheck
139 '';
140 installPhase = ''
141 runHook preInstall
142 mkdir -p $out/bin
143 cp daemon.py $out/bin/workspace-manager-daemon
144 chmod +x $out/bin/workspace-manager-daemon
145 wrapProgram $out/bin/workspace-manager-daemon \
146 --prefix PATH : ${python}/bin:${pkgs.sway}/bin
147 runHook postInstall
148 '';
149 meta.mainProgram = "workspace-manager-daemon";
150 };
151
152 # Open Firefox for the current workspace
153 packages.workspace-browser = pkgs.writeShellScriptBin "workspace-browser" ''
154 exec firefox "$@"
155 '';
156
157 # Native messaging host for the workspace-tabs Firefox extension
158 packages.workspace-tabs-native-host = pkgs.stdenv.mkDerivation {
159 pname = "workspace-tabs-native-host";
160 version = "0.1.0";
161 src = ./.;
162 nativeBuildInputs = [
163 pkgs.makeWrapper
164 pkgs.ruff
165 python.pkgs.mypy
166 ];
167 doCheck = true;
168 checkPhase = ''
169 runHook preCheck
170 ruff check workspace-tabs-host.py
171 ruff format --check workspace-tabs-host.py
172 mypy --strict workspace-tabs-host.py
173 runHook postCheck
174 '';
175 installPhase = ''
176 runHook preInstall
177 mkdir -p $out/bin $out/lib/mozilla/native-messaging-hosts
178 cp workspace-tabs-host.py $out/bin/workspace-tabs-host
179 chmod +x $out/bin/workspace-tabs-host
180 wrapProgram $out/bin/workspace-tabs-host \
181 --prefix PATH : ${python}/bin:${pkgs.sway}/bin
182
183 cat > $out/lib/mozilla/native-messaging-hosts/workspace_tabs.json <<EOF
184 {
185 "name": "workspace_tabs",
186 "description": "Native messaging host for Workspace Tabs extension",
187 "path": "$out/bin/workspace-tabs-host",
188 "type": "stdio",
189 "allowed_extensions": ["workspace-tabs@workspace-manager"]
190 }
191 EOF
192 runHook postInstall
193 '';
194 };
195
196 # Firefox extension for workspace tab management (packaged as .xpi)
197 packages.workspace-tabs-extension =
198 pkgs.runCommand "workspace-tabs-extension"
199 {
200 nativeBuildInputs = [ pkgs.zip ];
201 }
202 ''
203 mkdir -p $out
204 cd ${./firefox-extension}
205 zip -r "$out/workspace-tabs@workspace-manager.xpi" ./*
206 '';
207 };
208}