Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements direnv watch file functionality #224

Open
wants to merge 5 commits into
base: v5
Choose a base branch
from
Open
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
38 changes: 38 additions & 0 deletions fn/-z4h-base64-decode
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env zsh

eval "$_z4h_opt"

setopt cbases

typeset -g REPLY=

[[ -z $1 ]] && return
(( $#1 % 4 == 0 )) || return 1

local table='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

local c1 c2 c3 c4 res
local -i16 b1 b2 b3 b4

for c1 c2 c3 c4 in ${(s::)1//=/A}; do
((
b1 = $table[(ie)$c1] - 1,
b2 = $table[(ie)$c2] - 1,
b3 = $table[(ie)$c3] - 1,
b4 = $table[(ie)$c4] - 1,
b1 = b1 << 2 | b2 >> 4,
b2 = (b2 << 4) & 255 | b3 >> 2,
b3 = (b3 << 6) & 255 | b4
))
res+=($b1 $b2 $b3)
done

if [[ $1 == *= ]]; then
if [[ $1 == *== ]]; then
res[-2,-1]=()
else
res[-1]=()
fi
fi

printf -v REPLY ${(j:\:)res#0}
59 changes: 37 additions & 22 deletions fn/-z4h-direnv-hook
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env zsh

eval "$_z4h_opt"

unset _z4h_direnv_err
Expand All @@ -14,33 +13,49 @@ else
fi
fi

# { print -n '\x1f\x8b\x08\x00\x00\x00\x00\x00'; base64 -d <<<${${DIRENV_WATCHES//-/+}//_//} } | zcat 2>/dev/null

# zcat
# gzcat
# uncompress -c
# gunzip -c
# gzip -cd

local sig
local -a deps
local envrc=(./(../)#.envrc(NY1:a))

if (( $#envrc )); then
local -a deps=(
deps+=(
${XDG_DATA_HOME:-~/.local/share}/direnv/allow
${XDG_CONFIG_HOME:-~/.config}/{direnv.toml,config.toml})
local -a stat
local files=($^deps(N))
local non_files=(${deps:|files})
if zstat -A stat +mtime -- $envrc $files 2>/dev/null; then
local sig=$envrc$'\0'${(pj:\0:)stat}
else
local sig=stat-error
fi
elif [[ ! -v DIRENV_WATCHES ]]; then
${XDG_CONFIG_HOME:-~/.config}/{,direnv/}{direnv.toml,config.toml,direnvrc})
fi

if [[ -v DIRENV_WATCHES ]]; then
() {
local REPLY json
-z4h-base64-decode ${${DIRENV_WATCHES//-/+}//_//} || return
json=$(printf '\x1f\x8b\x08\x00\x00\x00\x00\x00%s' $REPLY | -z4h-zcat 2>/dev/null) #|| return
[[ $json == '['*']' ]] || return
# TODO: extract $(jq '.[] | .Path') from $json and append it to deps.

local -i i=1;
local pattern=${:-\"Path\":\"([^\"\\\\]|\\\\?)#\"}
local pathmatch;
pathmatch=${(*MSI:$i:)json##${~pattern}}
while [[ -n $pathmatch ]]; do
deps+=${(Q)pathmatch##(*):}
pathmatch=${(*MSI:$((++i)):)json##${~pattern}}
done

# TODO: cache those elements with $DIRENV_WATCHES as the key.
}
# TODO: handle errors from the above intelligently.
fi

if (( $#envrc + $#deps == 0 )); then
typeset -g _z4h_direnv_sig=none
return
fi

local -a stat
local files=($^deps(N))
local non_files=(${deps:|files})
if zstat -A stat +mtime -- $envrc $files 2>/dev/null; then
local sig=$envrc$'\0'${(pj:\0:)stat}
else
local sig=none
local sig=stat-error
fi

[[ $sig == ${_z4h_direnv_sig-} ]] && return
Expand Down
85 changes: 85 additions & 0 deletions fn/-z4h-json-parse
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env zsh
# Redneck json parsing. Yields correct results for any well-formed json document.
# Produces random garbage for invalid json.

local data
local -a params

data=$1; shift; params=( $@ );

data="${${data//$'\r'}##[[:space:]]#}"
[[ $data == ('{'|'[')* ]] || return
if [[ $data == '['*']' ]]
then
local arrayitem=''
local -a arraycontents
local -i depth=1
data[1]=
while (( depth > 0 ))
do
data=${data##[[:space:]]#}
[[ -n $data ]] || return
case $data[1] in
'{'|'[') arrayitem+=$data[1]; data[1]=; (( ++depth )) ;;
'}'|']') arrayitem+=$data[1]; data[1]=
(( --depth == 1 )) && { arraycontents+=($arrayitem); arrayitem='' } ;;
',') (( depth == 1 )) || arrayitem+=$data[1];
data[1]= ;;
':') arrayitem+=$data[1] data[1]= ;;
'"'|[[:alnum:].])
if [[ $data[1] == '"' ]]; then
local tail=${data##\"([^\"\\]|\\?)#\"}
else
local tail=${data##[[:alnum:].]#}
fi
[[ $tail == [[:space:][:punct:]]* ]] || return
arrayitem+=${data::-$#tail}; data=${tail}
;;
*) return 1 ;;
esac
done
(( ${#data##[[:space:]]#} == 0 )) || return
echo $arraycontents

elif [[ $data == '{'*'}' ]]
then
local field
local -A found
local -i depth=1
data[1]=
while (( depth > 0 ))
do
data=${data##[[:space:]]#}
[[ -n $data ]] || return
case $data[1] in
'{'|'[') data[1]=; (( ++depth )) ;;
'}'|']') data[1]=; (( --depth > 0 )) || return ;;
':') data[1]= ;;
',') data[1]=; field= ;;
'"'|[[:alnum:].])
if [[ $data[1] == '"' ]]; then
local tail=${data##\"([^\"\\]|\\?)#\"}
else
local tail=${data##[[:alnum:].]#}
fi
[[ $tail == [[:space:][:punct:]]* ]] || return
local s=${data::-$#tail}
data=${tail}
(( depth == 1 )) || continue
if [[ -z $field ]]; then
field=${s:-x}
elif [[ $field:*params ]]
then
(( ! $+found[$field] )) || return
[[ -n $s ]] || return
[[ $s != *($'\n'|'\')* ]] || return
found[$field]=$s
(( $#found == $#params )) && break
fi
;;
*) return 1 ;;
esac
done
echo ${(Q)found}
fi

11 changes: 11 additions & 0 deletions fn/-z4h-zcat
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env zsh

eval "$_z4h_opt"

local cmd
for cmd in zcat gzcat 'uncompress -c' 'gunzip -c' 'gzip -cd'; do
local words=($=cmd)
[[ -v commands[$words[1]] ]] || continue
$words || return
break
done