6 Commits

Author SHA1 Message Date
77bae03b14 chore: update rlru flake input 2026-06-19 21:50:32 -07:00
686023e006 nixos: update rlru input 2026-06-19 12:08:14 -07:00
f12285b7f7 Add x.com Chrome app scratchpad 2026-06-18 21:27:03 -07:00
0efb55f23f Enable hyprtasking workspace overview 2026-06-18 20:28:53 -07:00
30fb74b13b nixos: update rlru input 2026-06-18 16:19:52 -07:00
9bb090bb35 Update Claude and Codex flakes 2026-06-18 15:57:04 -07:00
13 changed files with 113 additions and 77 deletions

View File

@@ -258,9 +258,10 @@ Required behavior:
- A named scratchpad exists for spotify. - A named scratchpad exists for spotify.
- A named scratchpad exists for transmission. - A named scratchpad exists for transmission.
- A named scratchpad exists for volume. - A named scratchpad exists for volume.
- A named scratchpad exists for x.com.
- Scratchpads appear near-fullscreen and centered by default. - Scratchpads appear near-fullscreen and centered by default.
- The codex scratchpad can be tiled into the normal workspace when desired, - The codex, claude, and x.com scratchpads can be tiled into the normal
while retaining its summon/dismiss toggle. workspace when desired, while retaining their summon/dismiss toggles.
- Toggling a scratchpad deactivates fullscreen/tabbed state first. - Toggling a scratchpad deactivates fullscreen/tabbed state first.
- Floating scratchpads are hidden from normal workspace and window listings. - Floating scratchpads are hidden from normal workspace and window listings.
@@ -447,6 +448,7 @@ Required behavior:
- `Super+Alt+s` toggles the spotify scratchpad. - `Super+Alt+s` toggles the spotify scratchpad.
- `Super+Alt+t` toggles the transmission scratchpad. - `Super+Alt+t` toggles the transmission scratchpad.
- `Super+Alt+v` toggles the volume scratchpad. - `Super+Alt+v` toggles the volume scratchpad.
- `Super+Alt+x` toggles the x.com scratchpad.
Important behavior: Important behavior:

View File

@@ -88,17 +88,7 @@ function M.setup(ctx)
end end
local function setup_window_overview_bindings() local function setup_window_overview_bindings()
bind(main_mod .. " + SHIFT + C", hl.dsp.window.close(), desc("Close active window")) local function toggle_hyprtasking()
bind(main_mod .. " + SHIFT + Q", hl.dsp.exit(), desc("Exit Hyprland"))
bind(main_mod .. " + Tab", hyprexpo("toggle"), desc("Toggle hyprexpo workspace overview", overview_bind_opts))
bind(main_mod .. " + SHIFT + Tab", hyprwinview({
action = "show",
include_current_workspace = false,
start_in_filter_mode = true,
default_action = "bring",
}), desc("Show all-workspace window overview", overview_bind_opts))
bind(main_mod .. " + SHIFT + slash", hyprwinview({ action = "toggle-filter" }), desc("Toggle window overview filter", overview_bind_opts))
bind("ALT + Tab", function()
if hl.plugin and hl.plugin.hyprtasking and hl.plugin.hyprtasking.toggle then if hl.plugin and hl.plugin.hyprtasking and hl.plugin.hyprtasking.toggle then
hl.plugin.hyprtasking.toggle("cursor") hl.plugin.hyprtasking.toggle("cursor")
else else
@@ -110,8 +100,19 @@ function M.setup(ctx)
font_size = 13, font_size = 13,
}) })
end end
end, desc("Toggle hyprtasking workspace overview", overview_bind_opts)) end
bind("ALT + SHIFT + Tab", hyprexpo("on"), desc("Open hyprexpo workspace overview", overview_bind_opts))
bind(main_mod .. " + SHIFT + C", hl.dsp.window.close(), desc("Close active window"))
bind(main_mod .. " + SHIFT + Q", hl.dsp.exit(), desc("Exit Hyprland"))
bind(main_mod .. " + Tab", toggle_hyprtasking, desc("Toggle hyprtasking workspace overview", overview_bind_opts))
bind(main_mod .. " + SHIFT + Tab", hyprwinview({
action = "show",
include_current_workspace = false,
start_in_filter_mode = true,
default_action = "bring",
}), desc("Show all-workspace window overview", overview_bind_opts))
bind(main_mod .. " + SHIFT + slash", hyprwinview({ action = "toggle-filter" }), desc("Toggle window overview filter", overview_bind_opts))
bind("ALT + Tab", toggle_hyprtasking, desc("Toggle hyprtasking workspace overview", overview_bind_opts))
bind(main_mod .. " + G", hyprwinview({ bind(main_mod .. " + G", hyprwinview({
action = "show", action = "show",
start_in_filter_mode = true, start_in_filter_mode = true,
@@ -290,6 +291,9 @@ function M.setup(ctx)
bind(mod_alt .. " + V", function() bind(mod_alt .. " + V", function()
toggle_scratchpad("volume") toggle_scratchpad("volume")
end, desc("Toggle volume scratchpad")) end, desc("Toggle volume scratchpad"))
bind(mod_alt .. " + X", function()
toggle_scratchpad("x_com")
end, desc("Toggle X scratchpad"))
bind(mod_alt .. " + grave", function() bind(mod_alt .. " + grave", function()
toggle_scratchpad("dropdown") toggle_scratchpad("dropdown")
end, desc("Toggle dropdown scratchpad")) end, desc("Toggle dropdown scratchpad"))

View File

@@ -51,6 +51,12 @@ function M.setup(ctx)
command = "google-chrome-stable --profile-directory=Default --app=https://messages.google.com/web/conversations", command = "google-chrome-stable --profile-directory=Default --app=https://messages.google.com/web/conversations",
class = "chrome-messages.google.com", class = "chrome-messages.google.com",
}, },
x_com = {
command = "x-com-pwa",
classes = { "x-com-pwa", "chrome-x.com" },
title = "X",
allow_tiling = true,
},
transmission = { transmission = {
command = "transmission-gtk", command = "transmission-gtk",
class = "transmission-gtk", class = "transmission-gtk",

View File

@@ -89,6 +89,7 @@ function M.setup(ctx)
end end
if enable_hyprtasking and not verify_config then if enable_hyprtasking and not verify_config then
hl.plugin.load("/run/current-system/sw/lib/libhyprtasking.so") hl.plugin.load("/run/current-system/sw/lib/libhyprtasking.so")
os.execute("hyprctl eval 'hl.config({plugin={hyprtasking={full_render=true}}})' >/dev/null 2>&1 || true")
end end
if enable_hyprexpo and not enable_hyprtasking and not verify_config then if enable_hyprexpo and not enable_hyprtasking and not verify_config then
hl.plugin.load("/run/current-system/sw/lib/libhyprexpo.so") hl.plugin.load("/run/current-system/sw/lib/libhyprexpo.so")

View File

@@ -65,7 +65,7 @@ return {
-- hook fires on every popup commit). Re-enable once fixed upstream. -- hook fires on every popup commit). Re-enable once fixed upstream.
enable_hyprexpo = false, enable_hyprexpo = false,
enable_hyprwinview = true, enable_hyprwinview = true,
enable_hyprtasking = false, enable_hyprtasking = true,
enable_workspace_history = true, enable_workspace_history = true,
enable_hyprwobbly = true, enable_hyprwobbly = true,
enable_dynamic_cursors = true, enable_dynamic_cursors = true,

View File

@@ -147,6 +147,7 @@ spawnBindings =
, key (super .|. alt) xK_s (toggleScratchpad "spotify") , key (super .|. alt) xK_s (toggleScratchpad "spotify")
, key (super .|. alt) xK_t (toggleScratchpad "transmission") , key (super .|. alt) xK_t (toggleScratchpad "transmission")
, key (super .|. alt) xK_v (toggleScratchpad "volume") , key (super .|. alt) xK_v (toggleScratchpad "volume")
, key (super .|. alt) xK_x (toggleScratchpad "x-com")
, key (super .|. alt) xK_c (spawnAction "google-chrome-stable") , key (super .|. alt) xK_c (spawnAction "google-chrome-stable")
, key super xK_e (spawnAction "emacsclient --eval '(emacs-everywhere)'") , key super xK_e (spawnAction "emacsclient --eval '(emacs-everywhere)'")
, key (super .|. ctrl) xK_e (shiftFocusedToNextEmptyWorkspace False) , key (super .|. ctrl) xK_e (shiftFocusedToNextEmptyWorkspace False)
@@ -297,6 +298,8 @@ scratchpadDefinitions =
anyMatcher [titleContains "Transmission", appIdContains "transmission"] anyMatcher [titleContains "Transmission", appIdContains "transmission"]
, ScratchpadDefinition "volume" "pavucontrol" $ , ScratchpadDefinition "volume" "pavucontrol" $
anyMatcher [appIdMatches "Pavucontrol", appIdContains "pavucontrol"] anyMatcher [appIdMatches "Pavucontrol", appIdContains "pavucontrol"]
, ScratchpadDefinition "x-com" "x-com-pwa" $
anyMatcher [appIdMatches "x-com-pwa", appIdContains "chrome-x.com"]
] ]
anyMatcher :: [RiverWMWindowState -> Bool] -> RiverWMWindowState -> Bool anyMatcher :: [RiverWMWindowState -> Bool] -> RiverWMWindowState -> Bool

View File

@@ -244,6 +244,11 @@ slackSelector = className =? "Slack"
spotifySelector = className =? "Spotify" spotifySelector = className =? "Spotify"
transmissionSelector = fmap (isPrefixOf "Transmission") title transmissionSelector = fmap (isPrefixOf "Transmission") title
volumeSelector = className =? "Pavucontrol" volumeSelector = className =? "Pavucontrol"
xComSelector =
className =? "x-com-pwa"
<||> fmap ("chrome-x.com" `isInfixOf`) className
<||> (chromeSelectorBase <&&> title =? "X")
<||> fmap ("x.com" `isInfixOf`) title
virtualClasses = virtualClasses =
[ (chromeSelector, "Chrome") [ (chromeSelector, "Chrome")
@@ -261,6 +266,7 @@ slackCommand = "slack"
spotifyCommand = "spotify" spotifyCommand = "spotify"
transmissionCommand = "transmission-gtk" transmissionCommand = "transmission-gtk"
volumeCommand = "pavucontrol" volumeCommand = "pavucontrol"
xComCommand = "x-com-pwa"
-- Startup hook -- Startup hook
@@ -811,6 +817,7 @@ scratchpads =
, NS "spotify" spotifyCommand spotifySelector nearFullFloat , NS "spotify" spotifyCommand spotifySelector nearFullFloat
, NS "transmission" transmissionCommand transmissionSelector nearFullFloat , NS "transmission" transmissionCommand transmissionSelector nearFullFloat
, NS "volume" volumeCommand volumeSelector nearFullFloat , NS "volume" volumeCommand volumeSelector nearFullFloat
, NS "x-com" xComCommand xComSelector nearFullFloat
] ]
@@ -1018,6 +1025,7 @@ addKeys conf@XConfig { modMask = modm } =
, ((modalt, xK_s), doScratchpad "spotify") , ((modalt, xK_s), doScratchpad "spotify")
, ((modalt, xK_t), doScratchpad "transmission") , ((modalt, xK_t), doScratchpad "transmission")
, ((modalt, xK_v), doScratchpad "volume") , ((modalt, xK_v), doScratchpad "volume")
, ((modalt, xK_x), doScratchpad "x-com")
-- Specific program spawning -- Specific program spawning

View File

@@ -12,11 +12,7 @@ let
src = inputs.codex-desktop-linux; src = inputs.codex-desktop-linux;
patches = [ ./patches/codex-desktop-linux-gsettings-schemas.patch ]; patches = [ ./patches/codex-desktop-linux-gsettings-schemas.patch ];
}; };
claudeDesktopSource = pkgs.applyPatches { claudeDesktopSource = inputs.claude-desktop;
name = "claude-desktop-linux-patched";
src = inputs.claude-desktop;
patches = [ ./patches/claude-desktop-add-dir-multiple-matches.patch ];
};
claudeDesktopNodePty = pkgs.callPackage "${claudeDesktopSource}/nix/node-pty.nix" {}; claudeDesktopNodePty = pkgs.callPackage "${claudeDesktopSource}/nix/node-pty.nix" {};
claudeDesktop = pkgs.callPackage "${claudeDesktopSource}/nix/claude-desktop.nix" { claudeDesktop = pkgs.callPackage "${claudeDesktopSource}/nix/claude-desktop.nix" {
node-pty = claudeDesktopNodePty; node-pty = claudeDesktopNodePty;

View File

@@ -86,6 +86,34 @@
exec google-chrome-stable --profile-directory="$profile_dir" --new-window exec google-chrome-stable --profile-directory="$profile_dir" --new-window
''; '';
}; };
xComPwa = pkgs.writeShellApplication {
name = "x-com-pwa";
runtimeInputs = [
googleChromeCommandWrappers
pkgs.jq
];
text = ''
profile_args=()
local_state="''${CHROME_USER_DATA_DIR:-$HOME/.config/google-chrome}/Local State"
if [ -r "$local_state" ]; then
profile_dir="$(
jq -r '
(.profile.info_cache // {})
| to_entries
| sort_by(if .key == "Default" then 0 else 1 end, -(.value.active_time // 0))
| .[0].key // empty
' "$local_state" 2>/dev/null || true
)"
if [ -n "$profile_dir" ]; then
profile_args+=(--profile-directory="$profile_dir")
fi
fi
exec google-chrome-stable "''${profile_args[@]}" --class=x-com-pwa --app=https://x.com/
'';
};
googleChromeDesktopEntries = pkgs.runCommand "google-chrome-desktop-entries" {nativeBuildInputs = [pkgs.gnused];} '' googleChromeDesktopEntries = pkgs.runCommand "google-chrome-desktop-entries" {nativeBuildInputs = [pkgs.gnused];} ''
mkdir -p "$out/share/applications" mkdir -p "$out/share/applications"
@@ -242,6 +270,21 @@
}; };
}; };
xdg.desktopEntries.x-com-pwa = {
name = "X";
genericName = "Social Network";
comment = "Open x.com in a dedicated Chrome app window";
icon = "google-chrome";
terminal = false;
type = "Application";
categories = ["Network"];
startupNotify = true;
exec = "${xComPwa}/bin/x-com-pwa";
settings = {
StartupWMClass = "x-com-pwa";
};
};
xdg.configFile."ghostty/config" = { xdg.configFile."ghostty/config" = {
force = true; force = true;
text = '' text = ''
@@ -354,6 +397,7 @@
spotify spotify
spotifyWaylandPatch spotifyWaylandPatch
tor-browser tor-browser
xComPwa
# vscode # vscode
zulip zulip
] ]

36
nixos/flake.lock generated
View File

@@ -114,11 +114,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1781314818, "lastModified": 1781735477,
"narHash": "sha256-76EizPNWUOPLqwg6OP1KnX7XE7FEdrsJ2zQQaRKLYT4=", "narHash": "sha256-s66kETXt3w11uXH/njBfmmB1TOZn/MAmLL5VSqwOzqQ=",
"owner": "sadjow", "owner": "sadjow",
"repo": "claude-code-nix", "repo": "claude-code-nix",
"rev": "7c3c4413d8dbe29762fb5a9cb5443c3a72a9e18a", "rev": "9f444d93bf8029de1a9be31634be5a995ee5292c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -135,11 +135,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1781493849, "lastModified": 1781747722,
"narHash": "sha256-FIJdDGH1gb4HTppTTwJSSlH5xrKr8IfpinkAWpJUpto=", "narHash": "sha256-4aFy+NJ3aIVi7mIPLvIubnUuDy09FwDd+kG2QpagzCY=",
"owner": "aaddrick", "owner": "aaddrick",
"repo": "claude-desktop-debian", "repo": "claude-desktop-debian",
"rev": "2d1d0c59ffb94c0de8a0c5627d03c28099599792", "rev": "748b38854841db29b122d17515d4cf5add598994",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -159,11 +159,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1781038009, "lastModified": 1781761441,
"narHash": "sha256-MxvxXJ+EJxB9On3VfwjHLfeZFSB8Xlqz1IRpl43F76Q=", "narHash": "sha256-ZXJdWelt7SwbQTh18krnNgSS2SRveK4aoqO3xPdODD8=",
"owner": "sadjow", "owner": "sadjow",
"repo": "codex-cli-nix", "repo": "codex-cli-nix",
"rev": "75d6b831e036029e3d5f60b4f128dc0121730c37", "rev": "e3e7751853ece92c2a05ba4e8feee54afdb668c8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -183,11 +183,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1781761316, "lastModified": 1781785128,
"narHash": "sha256-hH+5JNKVugNkXEG0fLiGkvOySCmPERUcm+njP1+RLJw=", "narHash": "sha256-GQXqQIYLBNnPZNrmgt7aedf7PvO4QKKYjpVCAfowbQg=",
"owner": "ilysenko", "owner": "ilysenko",
"repo": "codex-desktop-linux", "repo": "codex-desktop-linux",
"rev": "9125911c8347c35177dfc76e2f5bce2b8b2e41d4", "rev": "933413a679df51886ea05d1d0eeb8057e44bf764",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1149,11 +1149,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1781106993, "lastModified": 1781534922,
"narHash": "sha256-BddvyVeSgLZU34hzI4yaXYILmfQN9n7oQJk4RbSaZM4=", "narHash": "sha256-jmzKIyRmpZLpxnR7DsWZ42bMzt+WeYDk+/x3FKSkovM=",
"owner": "yerlotic", "owner": "yerlotic",
"repo": "hyprtasking", "repo": "hyprtasking",
"rev": "3b3cb9d0b2fd4f6f4227b5b9539e849a37a17ddd", "rev": "1a82ca1ac79602e3bfd5ecb0a52c40c2bf818586",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1964,11 +1964,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1781817218, "lastModified": 1781930687,
"narHash": "sha256-McPiyjrbjctccv9weXYSwBxdP4cRF7heNBgFQ8VYP4c=", "narHash": "sha256-DT8yGwCsJuKedNRXceXx681x8Y1Wz+41/n7zP8HlURA=",
"owner": "rlrml", "owner": "rlrml",
"repo": "rlru", "repo": "rlru",
"rev": "01956ebab8adcd895c2dc72b7d1ea18139d5ab60", "rev": "577eb6379e3adc0fd5e7bd9fb80556dc931c3e18",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -198,6 +198,10 @@
src = inputs.hyprtasking; src = inputs.hyprtasking;
strictDeps = true; strictDeps = true;
postPatch = ''
substituteInPlace src/layout/layout_base.cpp \
--replace-fail 'e.element->passName()' 'e->element->passName()'
'';
nativeBuildInputs = nativeBuildInputs =
[ [
pkgs.pkg-config pkgs.pkg-config
@@ -287,10 +291,9 @@
hyprlandPluginPackages = hyprlandPluginPackages =
[ [
hyprNStack hyprNStack
hyprexpo
hyprwinview hyprwinview
hyprWorkspaceHistory hyprWorkspaceHistory
# hyprtasking # disabled: build failure against current Hyprland API hyprtasking
hyprDynamicCursors hyprDynamicCursors
hyprwobbly hyprwobbly
] ]

View File

@@ -204,6 +204,10 @@
src = inputs.hyprtasking; src = inputs.hyprtasking;
strictDeps = true; strictDeps = true;
postPatch = ''
substituteInPlace src/layout/layout_base.cpp \
--replace-fail 'e.element->passName()' 'e->element->passName()'
'';
nativeBuildInputs = [ nativeBuildInputs = [
pkgs.pkg-config pkgs.pkg-config
pkgs.meson pkgs.meson
@@ -291,10 +295,9 @@
hyprlandPluginPackages = hyprlandPluginPackages =
[ [
hyprNStack hyprNStack
hyprexpo
hyprwinview hyprwinview
hyprWorkspaceHistory hyprWorkspaceHistory
# hyprtasking # disabled: build failure against current Hyprland API hyprtasking
hyprDynamicCursors hyprDynamicCursors
hyprwobbly hyprwobbly
] ]

View File

@@ -1,34 +0,0 @@
diff --git a/scripts/patches/config.sh b/scripts/patches/config.sh
index 2453488..7c3f510 100644
--- a/scripts/patches/config.sh
+++ b/scripts/patches/config.sh
@@ -208,12 +208,7 @@ let patchCount = 0;
// Count assertion: exactly 1 match expected
const escaped = match[0].replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
- const allMatches = code.match(new RegExp(escaped, 'g'));
- if (allMatches && allMatches.length > 1) {
- console.error('FATAL: --add-dir pattern matches ' +
- allMatches.length + ' times (expected 1).');
- process.exit(1);
- }
+ const replacementCount = (code.match(new RegExp(escaped, 'g')) || []).length;
let filtered;
if (variant === 'for-of') {
@@ -230,9 +225,12 @@ let patchCount = 0;
'.push("--add-dir",' + iterVar + '))';
}
- code = code.replace(match[0], filtered);
+ code = code.split(match[0]).join(filtered);
console.log(' Filtered --add-dir dispatch (' +
- variant + ' variant)');
- patchCount++;
+ variant + ' variant' +
+ (replacementCount > 1
+ ? ', ' + replacementCount + ' identical matches'
+ : '') + ')');
+ patchCount += Math.max(1, replacementCount);
}
// ================================================================