diff --git a/fn/-z4h-direnv-hook b/fn/-z4h-direnv-hook index 60937e8..2dff49f 100644 --- a/fn/-z4h-direnv-hook +++ b/fn/-z4h-direnv-hook @@ -1,5 +1,4 @@ #!/usr/bin/env zsh - eval "$_z4h_opt" unset _z4h_direnv_err @@ -23,54 +22,20 @@ if (( $#envrc )); then ${XDG_CONFIG_HOME:-~/.config}/{,direnv/}{direnv.toml,config.toml,direnvrc}) fi - setopt localoptions extendedglob - local -a elements - elements=( "${=${unpacked:1:-1}//,\{/ {}" ) - - for obj in $elements[@]; do - (){ - local field - local -A found - data=${${obj//$'\r'}##[[:space:]]#} - - [[ $data == '{'* ]] || return - data[1]= - while true; do - data=${data##[[:space:]]#} - [[ -n $data ]] || return - case $data[1] in - ':') local tail=${data##([^,\\]|\\?)#} - local s=${data:1:-$#tail} - data=$tail - if [[ $field == (Path|Modtime) ]]; then - (( ! $+found[$field] )) || return - [[ -n $s ]] || return - [[ $s != *($'\n'|'\')* ]] || return - found[$field]=${(Q)s} - [[ ${(k)found} == 'Path' ]] && break - # (( $#found == 2 )) && break - fi - ;; - ',') data[1]=; field=;; - '"') local tail=${data##\"([^\"\\]|\\?)#} - local s=${data:1:-$#tail} - data=${tail:1} - [[ -z $field ]] && field=${s:-x} - ;; - *) return 1;; - esac - done - watched+=( ${(v)found} ) - } - done - unsetopt localoptions extendedglob 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=$(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. + + jsons=( $( -z4h-json-parse $json ) ) + + for object in $jsons; do + deps+=$( -z4h-json-parse $object Path ) + done + # TODO: cache those elements with $DIRENV_WATCHES as the key. } # TODO: handle errors from the above intelligently. diff --git a/fn/-z4h-json-parse b/fn/-z4h-json-parse new file mode 100644 index 0000000..5569a42 --- /dev/null +++ b/fn/-z4h-json-parse @@ -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 +