Shell – hook-like system for shell

shellzsh

I noticed I like to execute certain actions in a specific order.

A hook, as I see it, is basically "do something after event", where event, could be any command with parameters, such as git clone, git submodule add, cd, rm or any other.

I'd like to say, "if git add, do git status".
For example, I always: git add X; git status, and cd X; ls -la, and I can think of many more combinations like that, that I'd like to automate within my workflow.

There are 3 reasons why aliases \ functions won't easily work here:

  1. The main reason I don't think it can be easily done is that I have multiple function definitions and haven't found a way to override existing functions while still being able to use them.

I'll illustrate what I mean with an example: I use some zsh scripts by Nathan Broadbent called SCM Breeze – the scripts add a git() function that does things.

Suppose now I want to automate my workflow, and make it so that after every git clone, there is a cd to the directory made by the previous command (Here's how to do that). To do that, I'll use a git() function, right?

That function would override the SCM Breeze command, and I won't be able to use SCM Breeze.

  1. Aliases require me to remember things. I want this to happen automatically.
  2. It's not easy to maintain – I tried manually overriding each command, but changing things is really cumbersome, and I don't see myself doing it for every combination I can think of because of the complexity.

I use ZSH with OhMyZsh, if that helps.

Right now, I'm doing it with bash scripts (aliases and functions), but it feels as if I'm doing work very likely done by somebody else by now.
Anyone familier with a project that does that? help facilitate "hooks" in a tidy fashion?

Best Answer

Things that may help you:

The preexec hook function is called before every command line is executed (not before every command).

preexec() echo will execute: $1

precmd before each prompt.

precmd() echo executed: $history[$[HISTCMD-1]]

You can extend a function like this:

functions[git]='
  (){ '$functions[git]'; } "$@"; local myret=$?
  do-extra-stuff
  return $myret'

Or:

functions[git-old]=$functions[git]
git() {
  git-old "$@"
  local myret=$?
  do-extra-stuff || return $myret
}

The DEBUG trap is executed after each command:

trap 'echo $ZSH_DEBUG_CMD returned with $?' DEBUG

You can redefine the accept-line widget (mapped to Enter) to do stuff in there:

accept-line() {
  zle -R "going to run: $BUFFER"
  sleep 1
  zle .$WIDGET
}

zle -N accept-line
Related Question