fix(fish): fix TUI exit hang and typing latency in Zellij and Ghostty

This commit is contained in:
Noah Masur
2026-08-24 20:14:53 -06:00
parent b0b08d2475
commit 32989f1758
3 changed files with 23 additions and 6 deletions
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## 2026-08-25
- Fixed multi-second hang and permanent typing latency in Fish after exiting TUIs inside Zellij and Ghostty:
- Exported `fish_features = "no-query-term"` in `home.sessionVariables` and added `set -gx fish_features no-query-term` to Fish's top-level `shellInit`. Previous attempt (`set -a fish_features no-query-term` in `interactiveShellInit`) set a local variable inside an anonymous initialization function block that went out of scope immediately after startup. Furthermore, Fish reads `fish_features` at binary launch before interactive init functions run. Without `no-query-term` exported prior to Fish startup, Fish attempted terminal feature queries (Primary Device Attributes `DA1` / `\e[?c` and termcap) whenever a TUI (e.g. Neovim, Lazygit, Yazi) exited and returned control to Fish. Zellij drops or delays DA1 response sequences, causing Fish to block on a multi-second stdin timeout, followed by severe input reader desynchronization and typing latency on every subsequent keystroke.
- Disabled `programs.ghostty.enableFishIntegration` and conditionally sourced Ghostty's shell integration script in `shellInit` only when NOT running inside a multiplexer (`not set -q ZELLIJ` and `not set -q TMUX`). Sourcing Ghostty's shell integration inside Zellij sent duplicate and conflicting OSC 133 prompt markers and DECSCUSR cursor escape sequences to Zellij's PTY parser.
## 2026-08-16
- Fixed Zellij new tab directory tracking by adding `__fish_update_cwd_osc` override in `presets/programs/zellij.nix`. Fish's default OSC 7 sequence includes `$hostname`, which on macOS or dynamic network environments evaluates to `Noah-MacBook-Pro.local` or a domain suffix. Zellij compares the OSC 7 hostname against its system hostname (`Noah-MacBook-Pro`), finds a mismatch, and silently ignores the CWD update, leaving new tabs stuck in a previous directory or session default. Overriding `__fish_update_cwd_osc` to send `file://<PWD>` (empty hostname) ensures Zellij always updates its cached CWD on every `cd` and prompt render.
@@ -69,9 +69,6 @@ in
set -g fish_cursor_insert line
set -g fish_cursor_visual block
set -g fish_cursor_replace_one underscore
# Fix for lagging after exiting TUIs with Zellij and Ghostty
set -a fish_features no-query-term
'';
loginShellInit = "";
shellAbbrs = {
@@ -117,10 +114,17 @@ in
dr = "docker run --rm -it";
db = "docker build . -t";
};
shellInit = "";
shellInit = ''
# Fix for lagging/hanging after exiting TUIs inside terminal multiplexers like Zellij:
# Disable fish terminal querying at startup so fish does not query DA1/termcap on return.
set -gx fish_features no-query-term
'';
};
home.sessionVariables.fish_greeting = "";
home.sessionVariables = {
fish_greeting = "";
fish_features = "no-query-term";
};
};
}
@@ -23,7 +23,7 @@ in
package = if pkgs.stdenv.isDarwin then pkgs.ghostty-bin else pkgs.ghostty;
enableFishIntegration = true;
enableFishIntegration = false; # Handled conditionally below to avoid conflicts inside Zellij/TMUX
enableBashIntegration = true;
enableZshIntegration = true;
installBatSyntax = false; # The file doesn't seem to exist in the pkg
@@ -81,5 +81,12 @@ in
};
# Conditionally enable Ghostty fish shell integration only when NOT running inside multiplexers like Zellij/TMUX
programs.fish.shellInit = ''
if set -q GHOSTTY_RESOURCES_DIR; and not set -q ZELLIJ; and not set -q TMUX
source "$GHOSTTY_RESOURCES_DIR/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish"
end
'';
};
}