Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,32 @@ $ git clone https://github.com/yuki-yano/zeno.zsh.git
$ echo "source /path/to/dir/zeno.zsh" >> ~/.zshrc
```

`source /path/to/dir/zeno.zsh` remains the default installation method and
still performs the full initialization eagerly, so existing users can update
without changing their setup.

### Lazy-load for Zsh

If you want lazy-load, source `zeno-bootstrap.zsh` and use the upstream lazy key
API:

```zsh
source /path/to/dir/zeno-bootstrap.zsh
zeno-bind-default-keys --lazy
zsh-defer zeno-preload
```

For a custom bind:

```zsh
source /path/to/dir/zeno-bootstrap.zsh
zeno-register-lazy-widget zeno-completion
bindkey '^i' zeno-completion
```

Details for state variables, public APIs, and fallback behavior are in
[Lazy-load APIs for Zsh](#lazy-load-apis-for-zsh).

## Fish Shell Support (Experimental)

Fish support is experimental. A quick overview is included here; full
Expand Down Expand Up @@ -204,6 +230,14 @@ export ZENO_GIT_TREE="tree"
# git folder preview with color
# export ZENO_GIT_TREE="eza --tree"

# upstream default key set
# zeno-bind-default-keys

# upstream lazy key set
# source /path/to/dir/zeno-bootstrap.zsh
# zeno-bind-default-keys --lazy
# zsh-defer zeno-preload

if [[ -n $ZENO_LOADED ]]; then
bindkey ' ' zeno-auto-snippet

Expand Down Expand Up @@ -491,6 +525,52 @@ history:
togglePreview: ? # Toggle the preview window
```

## Lazy-load APIs for Zsh

Public state:

- `ZENO_BOOTSTRAPPED=1`: bootstrap is complete and zeno functions / widgets are available
- `ZENO_LOADED=1`: heavy init is complete and socket / history / preprompt are ready

Bootstrap (`source zeno-bootstrap.zsh`):

- sets `ZENO_ROOT`
- appends `bin` / `fpath`
- autoloads functions and widgets
- registers ZLE widgets with their original names
- sets `ZENO_BOOTSTRAPPED=1`

Heavy init (`zeno-init` / `zeno-ensure-loaded`):

- optional `deno cache`
- socket setup (`zeno-enable-sock`)
- history hooks (`zeno-history-hooks`)
- preprompt hooks (`zeno-preprompt-hooks`)
- sets `ZENO_LOADED=1`

Public APIs:

- `zeno-init`
- `zeno-ensure-loaded`
- `zeno-preload`
- `zeno-register-lazy-widget <widget>`
- `zeno-register-lazy-widgets <widget>...`
- `zeno-bind-default-keys`
- `zeno-bind-default-keys --lazy`

Builtin lazy fallback behavior:

- `zeno-completion` -> `ZENO_COMPLETION_FALLBACK`, otherwise `fzf-completion` or `expand-or-complete`
- `zeno-auto-snippet` -> `ZENO_AUTO_SNIPPET_FALLBACK`, otherwise `self-insert`
- `zeno-auto-snippet-and-accept-line` -> `accept-line`
- `zeno-history-selection` -> `history-incremental-search-backward`
- `zeno-smart-history-selection` -> `zeno-history-selection`, otherwise `history-incremental-search-backward`
- `zeno-insert-space` -> literal space insertion

This keeps widget names unchanged, so eager and lazy setups can both use
`bindkey '^i' zeno-completion` and similar bindings without user-defined wrapper
widgets.

## Fish usage

### Installation for Fish
Expand Down
51 changes: 51 additions & 0 deletions shells/zsh/functions/zeno-bind-default-keys
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#autoload

function zeno-bind-default-keys() {
emulate -L zsh

local lazy=0 arg
local -a lazy_widgets

for arg in "$@"; do
case "$arg" in
--lazy)
lazy=1
;;
*)
print -u2 -- "zeno-bind-default-keys: unsupported option: $arg"
return 1
;;
esac
done

lazy_widgets=(
zeno-auto-snippet
zeno-auto-snippet-and-accept-line
zeno-completion
zeno-insert-snippet
zeno-preprompt
zeno-preprompt-snippet
zeno-history-selection
)

if (( lazy )); then
zeno-register-lazy-widgets "${(@)lazy_widgets}" || return $?
else
zeno-ensure-loaded || return $?
local widget_name
for widget_name in "${(@)lazy_widgets}"; do
zle -N -- "$widget_name" || return $?
done
fi

bindkey ' ' zeno-auto-snippet
bindkey '^m' zeno-auto-snippet-and-accept-line
bindkey '^i' zeno-completion
bindkey '^xx' zeno-insert-snippet
bindkey '^x ' zeno-insert-space
bindkey '^x^m' accept-line
bindkey '^x^z' zeno-toggle-auto-snippet
bindkey '^xp' zeno-preprompt
bindkey '^xs' zeno-preprompt-snippet
bindkey '^r' zeno-history-selection
}
3 changes: 3 additions & 0 deletions shells/zsh/functions/zeno-enable-sock
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ function zeno-set-pid() {
}

autoload -Uz add-zsh-hook
add-zsh-hook -d precmd zeno-set-pid 2>/dev/null
add-zsh-hook -d chpwd zeno-onchpwd 2>/dev/null
add-zsh-hook -d zshexit zeno-stop-server 2>/dev/null
add-zsh-hook precmd zeno-set-pid
add-zsh-hook chpwd zeno-onchpwd
add-zsh-hook zshexit zeno-stop-server
Expand Down
11 changes: 11 additions & 0 deletions shells/zsh/functions/zeno-ensure-loaded
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#autoload

function zeno-ensure-loaded() {
emulate -L zsh

if [[ ${ZENO_LOADED-} == 1 ]]; then
return 0
fi

zeno-init "$@"
}
48 changes: 48 additions & 0 deletions shells/zsh/functions/zeno-init
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#autoload

function zeno-init() {
emulate -L zsh

if [[ ${ZENO_LOADED-} == 1 ]]; then
return 0
fi

if [[ -z ${ZENO_ROOT-} ]]; then
print -u2 -- "zeno-init: ZENO_ROOT is not set; source zeno-bootstrap.zsh first"
return 1
fi

if [[ -z ${ZENO_DISABLE_EXECUTE_CACHE_COMMAND-} ]]; then
command deno cache --node-modules-dir=auto --no-lock --no-check -- "${ZENO_ROOT}/src/cli.ts" ||
return $?
fi

if [[ -z ${ZENO_DISABLE_SOCK-} ]]; then
local raw_deno_version deno_version
local -a v_parts
raw_deno_version=$(deno -V 2>/dev/null)
v_parts=(${(s:.:)${${(z)raw_deno_version}[2]-0.0.0}})
v_parts[1]=${v_parts[1]//[^0-9]/}
v_parts[2]=${v_parts[2]//[^0-9]/}
v_parts[3]=${${v_parts[3]-0}%%[^0-9]*}
printf -v deno_version '%d%02d%02d' \
${v_parts[1]:-0} \
${v_parts[2]:-0} \
${v_parts[3]:-0}
if (( deno_version >= 11600 )); then
zeno-enable-sock || return $?
else
export ZENO_DISABLE_SOCK=1
fi
fi

if (( $+functions[zeno-history-hooks] )); then
zeno-history-hooks || return $?
fi

if (( $+functions[zeno-preprompt-hooks] )); then
zeno-preprompt-hooks || return $?
fi

export ZENO_LOADED=1
}
22 changes: 22 additions & 0 deletions shells/zsh/functions/zeno-lazy-widget-dispatch
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#autoload

function zeno-lazy-widget-dispatch() {
emulate -L zsh

local widget_name="${WIDGET-}"
if [[ -z $widget_name ]]; then
return 1
fi

if ! zeno-ensure-loaded; then
zeno-run-lazy-fallback "$widget_name"
return $?
fi

if (( $+functions[$widget_name] )); then
"$widget_name"
return $?
fi

return 1
}
7 changes: 7 additions & 0 deletions shells/zsh/functions/zeno-preload
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#autoload

function zeno-preload() {
emulate -L zsh

zeno-ensure-loaded "$@"
}
20 changes: 20 additions & 0 deletions shells/zsh/functions/zeno-register-lazy-widget
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#autoload

function zeno-register-lazy-widget() {
emulate -L zsh

local widget_name="$1"
if [[ -z $widget_name ]]; then
print -u2 -- "zeno-register-lazy-widget: widget name is required"
return 1
fi

if [[ ${ZENO_BOOTSTRAPPED-} != 1 ]]; then
print -u2 -- "zeno-register-lazy-widget: source zeno-bootstrap.zsh first"
return 1
fi

typeset -gA ZENO_LAZY_WIDGETS
ZENO_LAZY_WIDGETS[$widget_name]=1
zle -N -- "$widget_name" zeno-lazy-widget-dispatch
}
10 changes: 10 additions & 0 deletions shells/zsh/functions/zeno-register-lazy-widgets
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#autoload

function zeno-register-lazy-widgets() {
emulate -L zsh

local widget_name
for widget_name in "$@"; do
zeno-register-lazy-widget "$widget_name" || return $?
done
}
47 changes: 47 additions & 0 deletions shells/zsh/functions/zeno-run-lazy-fallback
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#autoload

function zeno-run-lazy-fallback() {
emulate -L zsh

local widget_name="$1"
local fallback_widget

case "$widget_name" in
zeno-completion)
fallback_widget=${ZENO_COMPLETION_FALLBACK:-${${widgets[fzf-completion]+fzf-completion}:-expand-or-complete}}
zle "$fallback_widget"
;;
zeno-auto-snippet)
fallback_widget=${ZENO_AUTO_SNIPPET_FALLBACK:-self-insert}
zle "$fallback_widget"
;;
zeno-auto-snippet-and-accept-line)
zle accept-line
;;
zeno-history-selection)
zle history-incremental-search-backward
;;
zeno-smart-history-selection)
if (( $+widgets[zeno-history-selection] || $+functions[zeno-history-selection] )); then
zle zeno-history-selection
else
zle history-incremental-search-backward
fi
;;
zeno-insert-space)
LBUFFER+=" "
if [[ -n ${RBUFFER+x} ]]; then
BUFFER="${LBUFFER}${RBUFFER}"
fi
if (( $+CURSOR )); then
CURSOR=${#LBUFFER}
fi
;;
zeno-insert-snippet|zeno-preprompt|zeno-preprompt-snippet|zeno-ghq-cd)
zle redisplay 2>/dev/null || true
;;
*)
return 1
;;
esac
}
2 changes: 1 addition & 1 deletion shells/zsh/widgets/zeno-completion
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ out=( "${(f)$(zeno-call-client-and-fallback --zeno-mode=completion \
)}" )

if [[ $out[1] != success ]]; then
zle ${ZENO_COMPLETION_FALLBACK:-${${functions[fzf-completion]+fzf-completion}:-expand-or-complete}}
zle ${ZENO_COMPLETION_FALLBACK:-${${widgets[fzf-completion]+fzf-completion}:-expand-or-complete}}
return
fi

Expand Down
Loading