8000 Option for caching generated Zsh code from external commands · Issue #528 · zimfw/zimfw · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Option for caching generated Zsh code from external commands #528
Open
@00dani

Description

@00dani

Is your feature request related to a problem? Please describe.

There are many programs that expect to be integrated into your shell by writing something like eval "$(theprogram init)" into your shell initialisation script. The program generates some shell code on the fly to hook itself into the appropriate parts of your shell. Direnv, Starship, Zoxide, and Carapace all recommend this installation method, for example, as do various "version manager" tools like rbenv and Pyenv.

There are also programs like vivid which expect to be called during shell initialisation and have their output saved to a parameter (LS_COLORS in this case), rather than directly evaluated as shell script. Expecting this seems to be less common - even similar tools like dircolors produce executable code that sets LS_COLORS rather than simply a value that needs to be saved to LS_COLORS - but it does happen, and I personally use vivid so I noticed.

However this code-generation approach can be a source of slowdown, because it needs to fork and exec the external program every time your shell starts. Additionally, the Zsh code generated by the external program cannot be zcompiled, since it is always produced on the fly. Since the actual generated code produced by these commands changes relatively rarely, it makes a lot of sense to prebuild it, zcompile it, and source that file on startup instead. Zim doesn't have a built-in way to do this, and I think it would be nice if it did.

Describe the solution you'd like

Inspired by a similar feature in the Znap tool, Zim could provide an additional command inside the zimrc called something like zeval, which would be invoked like this:

zeval direnv 'direnv hook zsh'
zeval zoxide 'zoxide init zsh'

When such a definition is "installed", Zim would run the provided command once, save the result to a new init.zsh file, and zcompile that file. Then on each launch, Zim would simply source that same init.zsh along with everything else.

Scenarios like vivid, where the command output needs to be saved to a parameter rather than simply evaluated, 7185 could be supported using a flag like this:

zeval vivid -p LS_COLORS 'vivid generate molokai'

When this is provided, rather than just writing the command's output directly to init.zsh, Zim could generate something like export LS_COLORS="output of command" and write that to init.zsh instead.

Zim could detect when the command in zimrc has been changed (say, from vivid generate molokai to vivid generate gruvbox-dark) and rerun it to produce a new cached result in that case, but otherwise keep using the cached output. Additionally a zimfw subcommand for invalidating cached evals would be useful.

Describe alternatives you've considered

I've already come up with a hacky way to implement this idea with Zim's existing features. It looks like this, in my zimrc:

zeval() {
  zmodule https://git.00dani.me/00dani/null --name zeval-$1 --on-pull "$2 >! init.zsh"
}
zeval-if-installed() {
  (( ${+commands[$1]} )) && zeval "$@"
}

# Installing other zmodules here in the normal way...

zeval-if-installed direnv 'direnv hook zsh'
zeval-if-installed zoxide 'zoxide init zsh'
zeval-if-installed starship 'starship init zsh --print-full-init'
zeval-if-installed vivid 'echo export LS_COLORS=${(qqq)$(vivid generate molokai)}'

zmodule completion
# Carapace calls compdef, so it needs to be sourced after compinit to work properly
zeval-if-installed carapace 'carapace _carapace zsh'

unfunction zeval zeval-if-installed

While this does absolutely work, this setup has a number of shortcomings: it's needlessly cloning an empty Git repository for every command I add, there's no simple way to invalidate the cached script when necessary, and the syntax I need to use for "save to a parameter" commands like vivid is honestly pretty gross!

I could fix that last issue myself by teaching my zeval function about the -p flag I suggested above, but the other problems really need support in Zim itself to be fixed properly.

Outside of my personal hack, I've found there are also plugins like evalcache and zsh-smartcache which implement this idea as a standalone utility. However these approaches have their own shortcomings: they don't support caching of a parameter assignment (so they don't work with vivid) , they run totally independently of your plugin manager so zimfw naturally can't manage them, and they both unconditionally shell out to md5 or md5sum to hash your command so you're still not actually avoiding a fork/exec by using them. Strangely, they also do not attempt to zcompile the cached output. Not sure why.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0