From e56446195832f7abaadf6a5597e5d4ae3937b4f0 Mon Sep 17 00:00:00 2001 From: Hobeom Date: Mon, 9 Mar 2026 22:57:30 +0900 Subject: [PATCH] feat(zellij): add session functions, convenience commands, and smart completions - Use functions for attach/delete/kill to enable session-aware completions - Add zr, zrf, ze convenience functions with conflict detection - Improve z prefix collision check (aliases, functions, commands) - Cache completions synchronously on first load, background on updates - Update README to document new functions and completion behavior Co-Authored-By: Claude Opus 4.6 --- plugins/zellij/README.md | 44 ++++++++++----- plugins/zellij/zellij.plugin.zsh | 92 ++++++++++++++++++++++++-------- 2 files changed, 101 insertions(+), 35 deletions(-) diff --git a/plugins/zellij/README.md b/plugins/zellij/README.md index 1a9a7ee9e..c4c8fd2ea 100644 --- a/plugins/zellij/README.md +++ b/plugins/zellij/README.md @@ -1,7 +1,8 @@ # zellij -This plugin provides aliases and completions for [zellij](https://zellij.dev/), the terminal workspace -(multiplexer). To use it, add `zellij` to the plugins array in your zshrc file. +This plugin provides aliases, functions, and completions for [zellij](https://zellij.dev/), +the terminal workspace (multiplexer). To use it, add `zellij` to the plugins array in your +zshrc file. ```zsh plugins=(... zellij) @@ -16,25 +17,42 @@ variable before oh-my-zsh is sourced: ZSH_ZELLIJ_PREFIX_Z=true ``` -> **Note:** If `z` is already aliased by another plugin (e.g., zoxide), the prefix stays `zj` -> even when `ZSH_ZELLIJ_PREFIX_Z` is set. +> **Note:** If `z` is already defined as an alias, function, or command by another plugin +> (e.g., zoxide), the `zj` prefix is used for the main `zellij` alias even when +> `ZSH_ZELLIJ_PREFIX_Z` is set. ## Aliases | Alias (default) | Alias (with `z`) | Command | Description | | ---------------- | ---------------- | ---------------------------- | ------------------------ | | `zj` | `z` | `zellij` | Zellij command | -| `zja` | `za` | `zellij attach` | Attach to a session | -| `zjd` | `zd` | `zellij delete-session` | Delete a session | -| `zjda` | `zda` | `zellij delete-all-sessions` | Delete all sessions | -| `zjk` | `zk` | `zellij kill-session` | Kill a session | -| `zjka` | `zka` | `zellij kill-all-sessions` | Kill all sessions | | `zjl` | `zl` | `zellij list-sessions` | List sessions | -| `zjr` | `zr` | `zellij run` | Run a command in a pane | | `zjs` | `zs` | `zellij -s` | Start a named session | +| `zjda` | `zda` | `zellij delete-all-sessions` | Delete all sessions | +| `zjka` | `zka` | `zellij kill-all-sessions` | Kill all sessions | +| `zjr` | — | `zellij run` | Run a command in a pane | + +## Functions + +| Function (default) | Function (with `z`) | Command | Description | +| ------------------- | ------------------- | ------------------------------ | --------------------------------- | +| `zja` | `za` | `zellij attach` | Attach to a session | +| `zjd` | `zd` | `zellij delete-session` | Delete a session | +| `zjk` | `zk` | `zellij kill-session` | Kill a session | + +The following convenience functions are always available (unless the name is already taken): + +| Function | Command | Description | +| -------- | ---------------------------- | ---------------------------------- | +| `zr` | `zellij run --` | Run a command in a pane | +| `zrf` | `zellij run --floating --` | Run a command in a floating pane | +| `ze` | `zellij edit` | Edit a file in a pane | ## Completions -This plugin caches the zellij completion script in the background (using the same approach as -the [gh](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/gh) plugin). On first load the -cache is generated; completions become available in the next shell session. +This plugin caches the zellij completion script. On first load the cache is generated +synchronously; subsequent updates (when the `zellij` binary is newer than the cache) happen in +the background. + +Session-aware completions are provided for `attach`, `delete-session`, and `kill-session` +functions — only relevant sessions (all, running, or exited) are offered. diff --git a/plugins/zellij/zellij.plugin.zsh b/plugins/zellij/zellij.plugin.zsh index e9c5eae89..34245e56a 100644 --- a/plugins/zellij/zellij.plugin.zsh +++ b/plugins/zellij/zellij.plugin.zsh @@ -2,34 +2,82 @@ if (( ! $+commands[zellij] )); then return fi -# Dynamic prefix: use "zj" by default, use "z" if ZSH_ZELLIJ_PREFIX_Z is set and "z" is available -if [[ -n "$ZSH_ZELLIJ_PREFIX_Z" ]] && (( ! $+aliases[z] )); then - _zellij_prefix="z" +if [[ -n ${ZSH_ZELLIJ_PREFIX_Z:-} ]]; then + _zellij_prefix=z else - _zellij_prefix="zj" + _zellij_prefix=zj fi -# Aliases -alias ${_zellij_prefix}='zellij' -alias ${_zellij_prefix}a='zellij attach' -alias ${_zellij_prefix}d='zellij delete-session' -alias ${_zellij_prefix}da='zellij delete-all-sessions' -alias ${_zellij_prefix}k='zellij kill-session' -alias ${_zellij_prefix}ka='zellij kill-all-sessions' + +if [[ -n ${ZSH_ZELLIJ_PREFIX_Z:-} ]] && (( ! $+aliases[z] && ! $+functions[z] && ! $+commands[z] )); then + alias z='zellij' +else + alias zj='zellij' +fi + +# alias ${_zellij_prefix}='zellij' alias ${_zellij_prefix}l='zellij list-sessions' -alias ${_zellij_prefix}r='zellij run' alias ${_zellij_prefix}s='zellij -s' +alias ${_zellij_prefix}da='zellij delete-all-sessions' +alias ${_zellij_prefix}ka='zellij kill-all-sessions' +[[ $_zellij_prefix != z ]] && alias ${_zellij_prefix}r='zellij run' -unset _zellij_prefix +eval "${_zellij_prefix}a() { command zellij attach \"\$@\"; }" +eval "${_zellij_prefix}d() { command zellij delete-session \"\$@\"; }" +eval "${_zellij_prefix}k() { command zellij kill-session \"\$@\"; }" -# Completion caching (same pattern as gh plugin) -# On first load, _zellij may not exist in fpath — autoload fails silently. -# The background command generates the cache file for subsequent sessions. -# Load order: plugin loads → compinit runs → next session picks up cached file. -if [[ ! -f "$ZSH_CACHE_DIR/completions/_zellij" ]]; then - typeset -g -A _comps - autoload -Uz _zellij - _comps[zellij]=_zellij +(( $+functions[zr] || $+aliases[zr] || $+commands[zr] )) || zr() { command zellij run -- "$@"; } +(( $+functions[zrf] || $+aliases[zrf] || $+commands[zrf] )) || zrf() { command zellij run --floating -- "$@"; } +(( $+functions[ze] || $+aliases[ze] || $+commands[ze] )) || ze() { command zellij edit "$@"; } + +_ZELLIJ_COMP_FILE="${ZSH_CACHE_DIR}/completions/_zellij" +mkdir -p "${_ZELLIJ_COMP_FILE:h}" + +if [[ ! -s $_ZELLIJ_COMP_FILE ]]; then + command zellij setup --generate-completion zsh >| "$_ZELLIJ_COMP_FILE" 2>/dev/null +elif [[ $commands[zellij] -nt $_ZELLIJ_COMP_FILE ]]; then + command zellij setup --generate-completion zsh >| "$_ZELLIJ_COMP_FILE" 2>/dev/null &! fi -zellij setup --generate-completion zsh >| "$ZSH_CACHE_DIR/completions/_zellij" &| +_omz_zellij_ls_raw() { + command zellij list-sessions --no-formatting 2>/dev/null || command zellij list-sessions 2>/dev/null +} + +_omz_zellij_all_sessions() { + emulate -L zsh + local out + local -a sessions + out="$(_omz_zellij_ls_raw)" + sessions=("${(@f)$(printf '%s\n' "$out" | LC_ALL=C sed -nE 's/^([^[:space:]]+).*/\1/p')}") + (( ${#sessions[@]} )) && compadd -Q -a sessions +} + +_omz_zellij_running_sessions() { + emulate -L zsh + local out + local -a sessions + out="$(_omz_zellij_ls_raw)" + sessions=("${(@f)$(printf '%s\n' "$out" | LC_ALL=C sed -nE '/EXITED/!s/^([^[:space:]]+).*/\1/p')}") + (( ${#sessions[@]} )) && compadd -Q -a sessions +} + +_omz_zellij_exited_sessions() { + emulate -L zsh + local out + local -a sessions + out="$(_omz_zellij_ls_raw)" + sessions=("${(@f)$(printf '%s\n' "$out" | LC_ALL=C sed -nE '/EXITED/s/^([^[:space:]]+).*/\1/p')}") + (( ${#sessions[@]} )) && compadd -Q -a sessions +} + +if (( $+functions[compdef] )); then + autoload -Uz _zellij + compdef _zellij zellij ${_zellij_prefix} ${_zellij_prefix}l ${_zellij_prefix}s + [[ $_zellij_prefix != z ]] && compdef _zellij ${_zellij_prefix}r + compdef _omz_zellij_all_sessions ${_zellij_prefix}a + compdef _omz_zellij_running_sessions ${_zellij_prefix}k + compdef _omz_zellij_exited_sessions ${_zellij_prefix}d +fi + +unset _ZELLIJ_COMP_FILE +unset _zellij_prefix