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

z4h's implementation of the direnv hook causes direnv's watch_file to not work #202

Open
hab25 opened this issue Jan 27, 2022 · 5 comments

Comments

@hab25
Copy link

hab25 commented Jan 27, 2022

I.e. in .zshrc, using

zstyle ':z4h:direnv'         enable 'yes'
# Show "loading" and "unloading" notifications from direnv.
zstyle ':z4h:direnv:success' notify 'yes'

instead of

eval "$(direnv hook zsh)"

will cause direnv to not reload when a file watched by watch_file changes. Example:


.envrc contents:

#!/bin/bash
direnv_version 2.29.0
watch_file foo.txt

changing the contents of foo.txt does not cause direnv to reload the environment.


The reload does occur if using eval "$(direnv hook zsh)" instead, in .zshrc.
This is happening on Pop!_OS 21.10 .

@romkatv
Copy link
Owner

romkatv commented Jan 27, 2022

Thanks for the bug report. I'll take a look when I get a chunk of free time.

In the interim you can disable the built-in direnv integration in zsh4humans and enable direnv via the usual means.

@mawwwrk
Copy link

mawwwrk commented May 14, 2022

Hi,

first, thank you for sharing your creations, i've been using p10k from for a long time, and z4h since i discovered it. i've also learned a lot from reading your explanations on why some things are done the way they are.

i did some digging in the z4h/fn folder, to see if i could do something about this issue, and it looks like the problem was already identified, because the code for getting and decoding $DIRENV_WATCHES is already there, just commented out.

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

the code for getting the timestamp is also already in the code:

if zstat -A stat +mtime -- $envrc $files 2>/dev/null; then

i'm attempting to expand on this - i'm using tr and cut to extract lines from json, then i was thinking of using awk to run through each line and check for changes, but before i proceed i thought i'd ask: it looks to me like this is something someone with more experience would be able to easily solve, and it looks like a solution was partially done already, so is there some gotcha i'm not seeing?

also, if i'm on the right track, are there any zsh functions (builtins? i'm not sure of the terminology) i can look at to make script better?

some_seq='\x1f\x8b\x08\x00\x00\x00\x00\x00'

json_string=$({
    print -n "${some_seq}" ;
    base64 -d <<<${${DIRENV_WATCHES//-/+}//_//}
} | zcat 2>/dev/null )

# returns the original json string as comma-delimited lines
tr_cut(){
    local lines
    lines=$(echo "${json_string}" | tr '}' '\n' | cut -c 3- )

    local values
    values=$(echo "${lines}" | tr -d '"' | tr ':' ',' | cut -d ',' -f 2,4,6 )

    echo "${values}"
}

@romkatv
Copy link
Owner

romkatv commented May 14, 2022

The comments you've found is my unfinished solution. In order to finish it, three things are necessary:

  1. Implement base64 decoding in pure zsh. This is necessary because base64 utility is not part of POSIX and currently z4h doesn't depend on it.
  2. Replace zcat with a function that checks which commands are available and uses those. All commands that do the trick are here:
    # zcat
    # gzcat
    # uncompress -c
    # gunzip -c
    # gzip -cd
  3. Implement a json parser in pure zsh. I already have one in powerlevel10k, so it's a matter of copying and adapting that code.

All of these are doable and aren't particularly difficult. I didn't do it because lazy.

@mawwwrk
Copy link

mawwwrk commented Jun 11, 2022

had a go at this. working as expected, so far.

Implement base64 decoding in pure zsh.

https://github.com/mawwwrk/zsh4humans/blob/05cc36cf1c22b68fc8b83acfad0fad6754d7dc72/fn/-z4h-direnv-hook#L32-L47

i think this is pure zsh. slightly concerned that it builds the hex->binary lookup array every time.

Replace zcat with a function that checks which commands are available and uses those.

https://github.com/mawwwrk/zsh4humans/blob/05cc36cf1c22b68fc8b83acfad0fad6754d7dc72/fn/-z4h-direnv-hook#L49-L55

returns the first value from the first available command that resembles a json array. it seems to work for all the apps except uncompress -c

Implement a json parser in pure zsh.

https://github.com/mawwwrk/zsh4humans/blob/05cc36cf1c22b68fc8b83acfad0fad6754d7dc72/fn/-z4h-direnv-hook#L57-L101

i grabbed your p10k json parser and mangled it a little, as it seems i really only need the file paths - then throw that back into the existing test for sig here:

https://github.com/mawwwrk/zsh4humans/blob/05cc36cf1c22b68fc8b83acfad0fad6754d7dc72/fn/-z4h-direnv-hook#L105-L106

thoughts?

also, a couple of questions:

https://github.com/romkatv/powerlevel10k/blob/406e6aa9e46429872c211d0c37517238ce9da3db/internal/p10k.zsh#L2249
field=${s:-x}
is this x here just an integer? i thought it might be a flag but upon closer inspection, there is a local -i x way up in the file.

local files=($^deps(N))

local files=($^deps(N))
i can't find this syntax $^ in the zsh guide. i assume its negation ^ and setting null_glob (N) ? how does it remove empty files/dirs?

@romkatv
Copy link
Owner

romkatv commented Jun 12, 2022

Wow, this looks great! I should have time to take a look at this in the next few days and merge it in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants