chore(fish): Update fish functions and configuration - #1907
Conversation
Update fish shell function configurations in home-manager. Modifies default fish config and adds/updates shell functions. - Update default.nix fish configuration - Update __tmux_bootstrap_default_session function - Add _caf_function for new functionality
|
📝 WalkthroughWalkthroughThis PR adds a new ChangesFish Shell Enhancements
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request registers a new fish function _caf_function (aliased as caf) to keep the machine awake when the lid is closed using caffeinate on macOS or systemd-inhibit on Linux. It also updates the tmux bootstrap script to warm the server on cold starts. The review feedback highlights two main points: first, a corresponding test file spec/fish/_caf_function_test.fish must be added to satisfy the repository's test coverage checks; second, the _caf_function script should be optimized to read the PID into a local variable instead of repeatedly calling cat inside command substitutions, which avoids potential syntax errors when the PID file is empty.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| }) | ||
| [ | ||
| "__tmux_bootstrap_default_session" | ||
| "_caf_function" |
There was a problem hiding this comment.
The repository has a test coverage spec (spec/fish_functions_coverage_spec.sh) that dynamically checks if every fish function has a corresponding test file under spec/fish/. Since you added _caf_function.fish, you must also add a corresponding test file spec/fish/_caf_function_test.fish to prevent the test suite from failing.
| function _caf_function --description "Keep the machine awake lid-closed (caffeinate / systemd-inhibit)" | ||
| set -l pid_file "$HOME/.local/state/caf.pid" | ||
|
|
||
| switch "$argv[1]" | ||
| case on | ||
| mkdir -p (dirname "$pid_file") | ||
| if test (uname) = Darwin | ||
| sudo pmset -a disablesleep 1 | ||
| caffeinate -dimsu & | ||
| else | ||
| systemd-inhibit --what=handle-lid-switch:sleep:idle \ | ||
| --who=caf --why=caf --mode=block sleep infinity & | ||
| end | ||
| echo $last_pid >"$pid_file" | ||
| disown | ||
| echo "caf on: awake lid-closed (pid "(cat "$pid_file")")" | ||
| case off | ||
| if test (uname) = Darwin | ||
| sudo pmset -a disablesleep 0 | ||
| end | ||
| if test -f "$pid_file" | ||
| kill (cat "$pid_file") 2>/dev/null | ||
| rm -f "$pid_file" | ||
| end | ||
| echo "caf off: normal sleep restored" | ||
| case status | ||
| if test (uname) = Darwin | ||
| pmset -g | string match -e disablesleep | ||
| else | ||
| systemd-inhibit --list 2>/dev/null | string match -e caf | ||
| end | ||
| if test -f "$pid_file"; and kill -0 (cat "$pid_file") 2>/dev/null | ||
| echo "caf active (pid "(cat "$pid_file")")" | ||
| else | ||
| echo "caf inactive" | ||
| end | ||
| case '' | ||
| # Toggle: active if the keeper pid is alive | ||
| if test -f "$pid_file"; and kill -0 (cat "$pid_file") 2>/dev/null | ||
| _caf_function off | ||
| else | ||
| _caf_function on | ||
| end | ||
| case '*' | ||
| echo "Usage: caf [on|off|status]" | ||
| return 1 | ||
| end | ||
| end |
There was a problem hiding this comment.
Using (cat "$pid_file") repeatedly inside command substitutions is inefficient and can lead to syntax errors if the PID file is empty or missing (e.g., kill -0 called with no arguments).
We can optimize this by reading the PID into a local variable using read -l pid < "$pid_file" and validating that it is non-empty before running kill. Additionally, we can reuse $last_pid directly in the on case instead of reading the file we just wrote.
function _caf_function --description "Keep the machine awake lid-closed (caffeinate / systemd-inhibit)"
set -l pid_file "$HOME/.local/state/caf.pid"
switch "$argv[1]"
case on
mkdir -p (dirname "$pid_file")
if test (uname) = Darwin
sudo pmset -a disablesleep 1
caffeinate -dimsu &
else
systemd-inhibit --what=handle-lid-switch:sleep:idle \\
--who=caf --why=caf --mode=block sleep infinity &
end
echo $last_pid >"$pid_file"
disown
echo "caf on: awake lid-closed (pid $last_pid)"
case off
if test (uname) = Darwin
sudo pmset -a disablesleep 0
end
if test -f "$pid_file"
read -l pid < "$pid_file"
if test -n "$pid"
kill $pid 2>/dev/null
end
rm -f "$pid_file"
end
echo "caf off: normal sleep restored"
case status
if test (uname) = Darwin
pmset -g | string match -e disablesleep
else
systemd-inhibit --list 2>/dev/null | string match -e caf
end
if test -f "$pid_file"
read -l pid < "$pid_file"
if test -n "$pid"; and kill -0 $pid 2>/dev/null
echo "caf active (pid $pid)"
else
echo "caf inactive"
end
else
echo "caf inactive"
end
case ''
# Toggle: active if the keeper pid is alive
set -l active no
if test -f "$pid_file"
read -l pid < "$pid_file"
if test -n "$pid"; and kill -0 $pid 2>/dev/null
set active yes
end
end
if test $active = yes
_caf_function off
else
_caf_function on
end
case '*'
echo "Usage: caf [on|off|status]"
return 1
end
end
| systemd-inhibit --what=handle-lid-switch:sleep:idle \ | ||
| --who=caf --why=caf --mode=block sleep infinity & | ||
| end | ||
| echo $last_pid >"$pid_file" |
There was a problem hiding this comment.
Re-running caf on leaks the prior keeper: This unconditionally overwrites $pid_file with the new $last_pid. If the user runs caf on twice (or caf on while a keeper is already alive), the previous caffeinate/systemd-inhibit process becomes an orphan that caf off will never kill (it only knows the most-recent PID). On Linux that orphan keeps holding a handle-lid-switch:sleep:idle inhibitor — visible in systemd-inhibit --list but no longer tracked here — until reboot or manual kill.
Consider short-circuiting case on with the same liveness check used in the toggle/status branches, e.g.:
if test -f "$pid_file"; and kill -0 (cat "$pid_file") 2>/dev/null
echo "caf already on (pid "(cat "$pid_file")")"
return 0
end| echo "caf on: awake lid-closed (pid "(cat "$pid_file")")" | ||
| case off | ||
| if test (uname) = Darwin | ||
| sudo pmset -a disablesleep 0 |
There was a problem hiding this comment.
Unconditional sudo pmset on Darwin off: This runs every time caf off (or the toggle path when nothing is active) is invoked on macOS, prompting for sudo even when there is no keeper to tear down. Mirror the pid-file guard used just below so the privileged call only happens when caf was actually on:
if test -f "$pid_file"
if test (uname) = Darwin
sudo pmset -a disablesleep 0
end
kill (cat "$pid_file") 2>/dev/null
rm -f "$pid_file"
endThere was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@home-manager/programs/fish/functions/__tmux_bootstrap_default_session.fish`:
- Around line 5-9: The warm-up call tmux start-server is currently executed
before validating the requested session name; move the tmux start-server
invocation so it only runs after the session name is accepted by the validation
branch (the case '*' handling) in the __tmux_bootstrap_default_session function,
ensuring that invalid sessions (e.g., when __tmux_bootstrap_default_session is
called with an unknown name) return early without touching tmux; update the
control flow to call tmux start-server right before building/attaching the
session (inside the branch that creates the session) so existing tests that
expect no tmux interaction on rejected names continue to pass.
In `@home-manager/programs/fish/functions/_caf_function.fish`:
- Around line 5-16: The "caf on" case is not idempotent: repeated runs spawn
multiple background inhibit processes while the PID file (pid_file) is
overwritten so "off" only stops the last one; fix by making the startup
idempotent—before starting, check pid_file for an existing PID(s), verify
whether that PID is still a running inhibitor process (or belongs to
caffeinate/systemd-inhibit), and if valid, do nothing; if stale, remove it and
then start the inhibitor and write its PID atomically; also ensure the code that
writes the PID uses the correct variable (last_pid) and that disown/echo handle
failures so orphan processes are not left behind (apply same logic to the "caf
on" branch for both Darwin caffeinate and systemd-inhibit paths and mirror in
the "caf off" handler to clean all recorded PIDs).
- Around line 21-23: Read the PID into a variable (e.g., pid="$(cat
"$pid_file")"), verify the process exists and its command line matches the
expected keep-awake command (e.g., using ps -p "$pid" -o args= or checking
/proc/"$pid"/cmdline) before calling kill, and only remove "$pid_file" after a
successful matched kill; if the PID is absent or the command does not match,
treat the pid file as stale and remove it without killing. Reference: pid_file
and the keep-awake command check around the block that currently runs kill (cat
"$pid_file") and rm -f "$pid_file".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 32ead906-5906-4f18-834f-b7eff05b219a
📒 Files selected for processing (3)
home-manager/programs/fish/default.nixhome-manager/programs/fish/functions/__tmux_bootstrap_default_session.fishhome-manager/programs/fish/functions/_caf_function.fish
| case on | ||
| mkdir -p (dirname "$pid_file") | ||
| if test (uname) = Darwin | ||
| sudo pmset -a disablesleep 1 | ||
| caffeinate -dimsu & | ||
| else | ||
| systemd-inhibit --what=handle-lid-switch:sleep:idle \ | ||
| --who=caf --why=caf --mode=block sleep infinity & | ||
| end | ||
| echo $last_pid >"$pid_file" | ||
| disown | ||
| echo "caf on: awake lid-closed (pid "(cat "$pid_file")")" |
There was a problem hiding this comment.
caf on is not idempotent and can leave orphan inhibit processes.
On Line 5 and Line 42, repeated starts create additional background inhibitors while Line 14 overwrites the PID file, so off only stops the latest one. This can leave the machine permanently inhibited unexpectedly.
Suggested fix
function _caf_function --description "Keep the machine awake lid-closed (caffeinate / systemd-inhibit)"
set -l pid_file "$HOME/.local/state/caf.pid"
switch "$argv[1]"
case on
mkdir -p (dirname "$pid_file")
+ if test -f "$pid_file"
+ set -l existing_pid (cat "$pid_file")
+ if test -n "$existing_pid"; and kill -0 "$existing_pid" 2>/dev/null
+ echo "caf already active (pid $existing_pid)"
+ return 0
+ end
+ rm -f "$pid_file"
+ end
if test (uname) = Darwin
sudo pmset -a disablesleep 1
caffeinate -dimsu &
else
systemd-inhibit --what=handle-lid-switch:sleep:idle \
--who=caf --why=caf --mode=block sleep infinity &
end
echo $last_pid >"$pid_file"
disown
echo "caf on: awake lid-closed (pid "(cat "$pid_file")")"Also applies to: 37-43
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@home-manager/programs/fish/functions/_caf_function.fish` around lines 5 - 16,
The "caf on" case is not idempotent: repeated runs spawn multiple background
inhibit processes while the PID file (pid_file) is overwritten so "off" only
stops the last one; fix by making the startup idempotent—before starting, check
pid_file for an existing PID(s), verify whether that PID is still a running
inhibitor process (or belongs to caffeinate/systemd-inhibit), and if valid, do
nothing; if stale, remove it and then start the inhibitor and write its PID
atomically; also ensure the code that writes the PID uses the correct variable
(last_pid) and that disown/echo handle failures so orphan processes are not left
behind (apply same logic to the "caf on" branch for both Darwin caffeinate and
systemd-inhibit paths and mirror in the "caf off" handler to clean all recorded
PIDs).
| if test -f "$pid_file" | ||
| kill (cat "$pid_file") 2>/dev/null | ||
| rm -f "$pid_file" |
There was a problem hiding this comment.
PID-file kill is unsafe without process identity validation.
On Line 22, killing an unvalidated PID from disk can terminate an unrelated process after PID reuse. Validate that the PID still belongs to the expected keep-awake command before sending kill.
Suggested fix
case off
if test (uname) = Darwin
sudo pmset -a disablesleep 0
end
if test -f "$pid_file"
- kill (cat "$pid_file") 2>/dev/null
+ set -l pid (cat "$pid_file")
+ set -l cmd (ps -p "$pid" -o command= 2>/dev/null)
+ if string match -rq 'caffeinate|systemd-inhibit|sleep infinity' -- "$cmd"
+ kill "$pid" 2>/dev/null
+ else
+ echo "caf off: refusing to kill unrecognized pid $pid"
+ end
rm -f "$pid_file"
end
echo "caf off: normal sleep restored"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@home-manager/programs/fish/functions/_caf_function.fish` around lines 21 -
23, Read the PID into a variable (e.g., pid="$(cat "$pid_file")"), verify the
process exists and its command line matches the expected keep-awake command
(e.g., using ps -p "$pid" -o args= or checking /proc/"$pid"/cmdline) before
calling kill, and only remove "$pid_file" after a successful matched kill; if
the PID is absent or the command does not match, treat the pid file as stale and
remove it without killing. Reference: pid_file and the keep-awake command check
around the block that currently runs kill (cat "$pid_file") and rm -f
"$pid_file".
There was a problem hiding this comment.
5 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="home-manager/programs/fish/functions/_caf_function.fish">
<violation number="1" location="home-manager/programs/fish/functions/_caf_function.fish:9">
P2: `caf on` is not idempotent; repeated calls can leak extra inhibitor processes that `caf off` will not stop.</violation>
<violation number="2" location="home-manager/programs/fish/functions/_caf_function.fish:19">
P2: `sudo pmset -a disablesleep 0` runs unconditionally on Darwin whenever `caf off` is invoked, prompting for sudo even when caf was never turned on (no PID file exists). Guard it with the same `test -f "$pid_file"` check used for the kill below, so the privileged call only fires when caf was actually active.</violation>
<violation number="3" location="home-manager/programs/fish/functions/_caf_function.fish:22">
P1: The PID file is trusted without validation, so `caf off` can kill the wrong process.</violation>
</file>
<file name="home-manager/programs/fish/default.nix">
<violation number="1" location="home-manager/programs/fish/default.nix:230">
P2: The repository has a test coverage spec (`spec/fish_functions_coverage_spec.sh`) that checks every fish function has a corresponding test file. Adding `_caf_function` without a corresponding `spec/fish/_caf_function_test.fish` will cause the test suite to fail.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| sudo pmset -a disablesleep 0 | ||
| end | ||
| if test -f "$pid_file" | ||
| kill (cat "$pid_file") 2>/dev/null |
There was a problem hiding this comment.
P1: The PID file is trusted without validation, so caf off can kill the wrong process.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/functions/_caf_function.fish, line 22:
<comment>The PID file is trusted without validation, so `caf off` can kill the wrong process.</comment>
<file context>
@@ -0,0 +1,48 @@
+ sudo pmset -a disablesleep 0
+ end
+ if test -f "$pid_file"
+ kill (cat "$pid_file") 2>/dev/null
+ rm -f "$pid_file"
+ end
</file context>
| mkdir -p (dirname "$pid_file") | ||
| if test (uname) = Darwin | ||
| sudo pmset -a disablesleep 1 | ||
| caffeinate -dimsu & |
There was a problem hiding this comment.
P2: caf on is not idempotent; repeated calls can leak extra inhibitor processes that caf off will not stop.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/functions/_caf_function.fish, line 9:
<comment>`caf on` is not idempotent; repeated calls can leak extra inhibitor processes that `caf off` will not stop.</comment>
<file context>
@@ -0,0 +1,48 @@
+ mkdir -p (dirname "$pid_file")
+ if test (uname) = Darwin
+ sudo pmset -a disablesleep 1
+ caffeinate -dimsu &
+ else
+ systemd-inhibit --what=handle-lid-switch:sleep:idle \
</file context>
| echo "caf on: awake lid-closed (pid "(cat "$pid_file")")" | ||
| case off | ||
| if test (uname) = Darwin | ||
| sudo pmset -a disablesleep 0 |
There was a problem hiding this comment.
P2: sudo pmset -a disablesleep 0 runs unconditionally on Darwin whenever caf off is invoked, prompting for sudo even when caf was never turned on (no PID file exists). Guard it with the same test -f "$pid_file" check used for the kill below, so the privileged call only fires when caf was actually active.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/functions/_caf_function.fish, line 19:
<comment>`sudo pmset -a disablesleep 0` runs unconditionally on Darwin whenever `caf off` is invoked, prompting for sudo even when caf was never turned on (no PID file exists). Guard it with the same `test -f "$pid_file"` check used for the kill below, so the privileged call only fires when caf was actually active.</comment>
<file context>
@@ -0,0 +1,48 @@
+ echo "caf on: awake lid-closed (pid "(cat "$pid_file")")"
+ case off
+ if test (uname) = Darwin
+ sudo pmset -a disablesleep 0
+ end
+ if test -f "$pid_file"
</file context>
| }) | ||
| [ | ||
| "__tmux_bootstrap_default_session" | ||
| "_caf_function" |
There was a problem hiding this comment.
P2: The repository has a test coverage spec (spec/fish_functions_coverage_spec.sh) that checks every fish function has a corresponding test file. Adding _caf_function without a corresponding spec/fish/_caf_function_test.fish will cause the test suite to fail.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/default.nix, line 230:
<comment>The repository has a test coverage spec (`spec/fish_functions_coverage_spec.sh`) that checks every fish function has a corresponding test file. Adding `_caf_function` without a corresponding `spec/fish/_caf_function_test.fish` will cause the test suite to fail.</comment>
<file context>
@@ -226,6 +227,7 @@
})
[
"__tmux_bootstrap_default_session"
+ "_caf_function"
"_cawxe_function"
"_cawxeh_function"
</file context>
Verifies argument handling, correct usage output, and graceful behavior when no active keeper process is detected. Uses temporary directories and command stubs to ensure isolated and repeatable test execution.
Update fish shell function configurations in home-manager.
Changes
Details
Modifies fish shell setup in home-manager to improve function configuration and add new shell utilities.
Summary by cubic
Add a new fish “caf” utility to keep the machine awake and wire it into the config. Warm the tmux server during bootstrap to prevent client freezes on cold start; add tests for “caf” to validate usage and inactive-state handling.
New Features
_caf_function: keeps the machine awake lid-closed usingpmset/caffeinate(macOS) orsystemd-inhibit(Linux); supports on/off/status/toggle and tracks PID at~/.local/state/caf.pid.cafabbreviation and loads_caf_functioninhome-manager/programs/fish/default.nix.caf: check argument handling, usage output, and no-keeper behavior with isolated HOME and stubbed commands.Bug Fixes
__tmux_bootstrap_default_session: calltmux start-serverbefore creating/attaching sessions to avoid freezes while plugins initialize.Written for commit 800f576. Summary will update on new commits.