From 6a511c43319657a34f18e4caa6a3c987718db474 Mon Sep 17 00:00:00 2001 From: Marco Di Sarno Date: Thu, 11 Apr 2024 10:58:28 +0200 Subject: [PATCH] Add auto install feature for pre-commit plugin --- plugins/pre-commit/README.md | 47 ++++++++++++++++ plugins/pre-commit/pre-commit.plugin.zsh | 71 ++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/plugins/pre-commit/README.md b/plugins/pre-commit/README.md index e6d80d369..8721fca1a 100644 --- a/plugins/pre-commit/README.md +++ b/plugins/pre-commit/README.md @@ -17,3 +17,50 @@ plugins=(... pre-commit) | prcr | `pre-commit run` | The `pre-commit run` command | | prcra | `pre-commit run --all-files` | Run pre-commit hooks on all files | | prcrf | `pre-commit run --files` | Run pre-commit hooks on a given list of files | + + +## Auto install `pre-commit` hook + +This plugin can auto install the defined pre-commit hooks from a `.pre-commit-config.yaml`, if it detects that file in your current working dir. + +## Settings + +#### ZSH_PRE_COMMIT_AUTO_INSTALL + +Set `ZSH_PRE_COMMIT_AUTO_INSTALL` to control auto install. + +- `prompt` (default) will prompt on a per-directory basis +- `off` will turn the feature off +- any other setting will auto install without prompting. + +```zsh +# in ~/.zshrc, before Oh My Zsh is sourced: +ZSH_PRE_COMMIT_AUTO_INSTALL=prompt|off|anything_else_is_on +``` + +#### ZSH_PRE_COMMIT_CONFIG_FILE + +The plugin will default to use `.pre-commit-config.yaml`. + +You can override this with the variable `$ZSH_PRE_COMMIT_CONFIG_FILE`, like so: + +```zsh +# in ~/.zshrc, before Oh My Zsh is sourced: +ZSH_PRE_COMMIT_CONFIG_FILE=.my-custom-pre-commit-config.yaml +``` + +#### ZSH_PRE_COMMIT_INSTALLED_LIST + +The default behavior of the plugin is to prompt for installation. It will also remember it did so, which will be cached in a list to be defined by: `$ZSH_PRE_COMMIT_INSTALLED_LIST`. + +The details for the three options are: +- **Y**es: install and write the current dir into the list. +- **A**sk again for this directory: don't do anything now. +- **N**ever ask again for this directory: don't install, but write the current dir into the list. + +By default, this list will be here `${ZSH_CACHE_DIR:-$ZSH/cache}/pre-commit-installed.list"`, but you can set the filename of that list to whatever you want: + +```zsh +# in ~/.zshrc, before Oh My Zsh is sourced: +ZSH_PRE_COMMIT_INSTALLED_LIST=/path/to/list +``` diff --git a/plugins/pre-commit/pre-commit.plugin.zsh b/plugins/pre-commit/pre-commit.plugin.zsh index c3d0c6290..63099831e 100644 --- a/plugins/pre-commit/pre-commit.plugin.zsh +++ b/plugins/pre-commit/pre-commit.plugin.zsh @@ -6,3 +6,74 @@ alias prcau='pre-commit autoupdate' alias prcr='pre-commit run' alias prcra='pre-commit run --all-files' alias prcrf='pre-commit run --files' + +# Auto install + +## Settings + +# Filename of the pre-commit file to look for +: ${ZSH_PRE_COMMIT_CONFIG_FILE:=.pre-commit-config.yaml} + +# Path to the file containing installed paths +: ${ZSH_PRE_COMMIT_INSTALLED_LIST:="${ZSH_CACHE_DIR:-$ZSH/cache}/pre-commit-installed.list"} + +# Default setting for auto install to prompt +: ${ZSH_PRE_COMMIT_AUTO_INSTALL:="prompt"} + +## Functions + +autoload -U add-zsh-hook +if [[ "$ZSH_PRE_COMMIT_AUTO_INSTALL" == "off" ]]; then + add-zsh-hook -d chpwd auto_install_pre_commit + return +fi + +auto_install_pre_commit() { + if [[ ! -f "$ZSH_PRE_COMMIT_CONFIG_FILE" ]]; then + return + fi + + local dirpath="${PWD:A}" + + # early return if already installed + if command grep -Fx -q "$dirpath" "$ZSH_PRE_COMMIT_INSTALLED_LIST" &>/dev/null; then + return + fi + + if [[ "$ZSH_PRE_COMMIT_AUTO_INSTALL" == "prompt" ]]; then + local confirmation + + touch "$ZSH_PRE_COMMIT_INSTALLED_LIST" + + # get cursor column and print new line before prompt if not at line beginning + local column + echo -ne "\e[6n" > /dev/tty + read -t 1 -s -d R column < /dev/tty + column="${column##*\[*;}" + [[ $column -eq 1 ]] || echo + + # print same-line prompt and output newline character if necessary + echo -n "pre-commit: found '$ZSH_PRE_COMMIT_CONFIG_FILE' file. Install hooks? ([Y]es/[A]sk again/[N]ever)" + read -k 1 confirmation + [[ "$confirmation" = $'\n' ]] || echo + + # check input + case "$confirmation" in + [yY]) ;; # yes + [aA]) return ;; # ask again + [nN]) echo "$dirpath" >> "$ZSH_PRE_COMMIT_INSTALLED_LIST"; return ;; # never ask again + *) return ;; # interpret anything else as ask again + esac + fi + + # check if pre-commit is installed + if ! type pre-commit > /dev/null; then + echo "You need to install pre-commit first. https://pre-commit.com/#install can help you out."; + return + fi + + pre-commit install && echo "$dirpath" >> "$ZSH_PRE_COMMIT_INSTALLED_LIST" +} + +add-zsh-hook chpwd auto_install_pre_commit +auto_install_pre_commit