Skip to content

Commit

Permalink
Fix repo-less use of znap eval
Browse files Browse the repository at this point in the history
  • Loading branch information
marlonrichert committed May 4, 2023
1 parent 62abac7 commit 4ec387d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 46 deletions.
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ To run `znap pull` on specific repos only, including ones you have set to be exc
## `.zshrc` optimization
Using Znap to optimize your Zsh config can be as simple as this:
```sh
[[ -r ~/Repos/znap/znap.zsh ]] ||
git clone --depth 1 -- https://github.com/marlonrichert/zsh-snap.git ~/Repos/znap

# `znap prompt` makes your prompt visible in just 15-40ms!
znap prompt sindresorhus/pure

Expand All @@ -74,13 +77,27 @@ file](.zshrc).
Additionaly, Znap makes it so that you actually need to have _less_ in your `.zshrc` file, by
automating several tasks for you.

### Faster `eval`
Use `znap eval ... <command>` to cache the output of `<command>`, compile it, and then `source` it (instead of `eval` it):
```sh
znal eval <name> '<command>'
```
This can be up 10 times faster than a regular `eval "$( <command> )"` statement! If you pass a repo as the first
argument, then Znap will `eval` the command output inside the given repo and will invalidate the cache whenever the repo
is update. Otherwise, the cache will be invalidated whenever `<command>` changes. Caches are stored in
`${XDG_CACHE_HOME:-$HOME/.cache}/zsh-snap/eval`.

### Automatic `compinit` and `bashcompinit`
Note that the above example does not include any call to
[`complist`](http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html#The-zsh_002fcomplist-Module),
[`compinit`, or
`bashcompinit`](http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Initialization) in
the `.zshrc` file. That is because Znap will run these for you as needed.

Znap also regenerates your [comp dump
file](http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Use-of-compinit) automatically whenever you update a
repo, install a repo, or change your `.zshrc` file.

If necessary, you can let Znap pass arguments to `compinit` as follows:
```sh
zstyle '*:compinit' arguments -D -i -u -C -w
Expand All @@ -98,18 +115,6 @@ zstyle ':znap:*' auto-compile no
In any case, you can compile sources manually at any time with
`znap compile [ <dir> | <file> ] ...`.

### Automatic cache invalidation
Znap automatically regenerates your [comp dump
file](http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Use-of-compinit) whenever you
install or update a repo or change your `.zshrc` file.

Znap also automatically regenerates its internal cache for each command when…
* …a cache file is older than the Git index of its associated repo.
* …the last argument of the `znap eval` statements that produced it has changed. So, if the last
argument to `znap eval` contains a variable, then its cached output will be regenerated whenever
the variable changes. See the [example `.zshrc` file](.zshrc) for a practical use of this.
* …the cache file is missing. You can delete them manually from `$XDG_CACHE_HOME/zsh-snap/eval`.

## Automatic `git maintenance`
When using `git` 2.31.0 or newer, Znap automatically enables `git maintenance` in each repo that it
manages. This automatically optimizes your repos in the background, so that your `git` and `znap`
Expand Down
62 changes: 28 additions & 34 deletions functions/.znap.eval
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,48 @@
# args: ( <repo> | <name> ) <command>
zmodload -F zsh/files b:zf_mkdir

# TODO: deprecate this and provide `znap cache <key> <command>` instead.

if (( $# < 2 )); then
print -u2 'znap eval: not enough arguments'
.znap.help eval
return $(( sysexits[(i)USAGE] + 63 ))
fi

.znap.eval.generate() {
(
private _P__repo=$1 _P__cache_file=$2
shift 2
private _P__header="#${(q)@}"

local __line
[[ -r $_P__cache_file ]] &&
IFS='' read -r __line < $_P__cache_file

if [[ $__line != $_P__header ||
( -d $_P__repo && -f $_P__repo/${GIT_DIR:-.git}/index &&
$_P__repo/${GIT_DIR:-.git}/index -nt $_P__cache_file ) ]]; then
[[ -d $_P__repo ]] &&
cd -q -- $_P__repo
print -r -- "$_P__header" >| $_P__cache_file
eval "$@" >>| $_P__cache_file
.znap.compile $_P__cache_file
fi
)
}

local gitdir=''
..znap.repos-dir

if [[ $1 == */* ]]; then
.znap.clone $1 ||
return
fi

private _P__repo=~[$1] __cache_dir=$XDG_CACHE_HOME/zsh-snap/eval
shift

zf_mkdir -pm 0700 $__cache_dir
private _P__cache_file=$__cache_dir/${_P__repo:t}.zsh

if [[ -r $_P__cache_file ]]; then
.znap.eval.generate "$_P__repo" "$_P__cache_file" "$@" &|
private _P__repo=~[$1]
private _P__name=${_P__repo#$gitdir}
else
print -r "znap eval: generating cache for $*"
.znap.eval.generate "$_P__repo" "$_P__cache_file" "$@"
local _P__name=$1 _P__repo=
fi
private _P__cmd=$2

private _P__cache_dir=$XDG_CACHE_HOME/zsh-snap/eval
zf_mkdir -pm 0700 $_P__cache_dir
private _P__cache_file=$_P__cache_dir/${_P__name}.zsh

[[ -r $_P__cache_file ]] ||
print -r "znap eval: generating cache for ${(q+)_P__cmd}"

private _P__line= _P__header="#${(q+)_P__cmd}" _P__index=$_P__repo/.git/index
(
[[ -r $_P__cache_file ]] &&
IFS='' read -r _P__line < $_P__cache_file

if [[ $_P__line != $_P__header ]] ||
[[ -n $_P__repo && -f $_P__index && $_P__index -nt $_P__cache_file ]]; then
[[ -d $_P__repo ]] &&
cd -q -- $_P__repo
print -r -- "$_P__header" >! $_P__cache_file
eval "$_P__cmd" >>! $_P__cache_file
.znap.compile $_P__cache_file
fi
)

# Wrap in a named function for profiling purposes.
.znap.eval:${_P__cache_file:t}() {
Expand Down

0 comments on commit 4ec387d

Please sign in to comment.