src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/hook.go (about)

     1  package eval
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"src.elv.sh/pkg/diag"
     7  	"src.elv.sh/pkg/eval/vals"
     8  )
     9  
    10  // CallHook runs all the functions in the list "hook", with "args".
    11  //
    12  // If "evalCfg" is not specified, the standard files will be used for IO.
    13  //
    14  // TODO: Eventually all callers should supply evalCfg. In general it's not
    15  // correct to use standard files:
    16  //
    17  // - Chdir hooks should use the frame from which the chdir is triggered.
    18  // - Editor lifecycle hooks should use the editor's TTY.
    19  func CallHook(ev *Evaler, evalCfg *EvalCfg, name string, hook vals.List, args ...any) {
    20  	if hook.Len() == 0 {
    21  		return
    22  	}
    23  
    24  	if evalCfg == nil {
    25  		ports, cleanup := PortsFromStdFiles(ev.ValuePrefix())
    26  		defer cleanup()
    27  		evalCfg = &EvalCfg{Ports: ports}
    28  	}
    29  
    30  	callCfg := CallCfg{Args: args, From: "[hook " + name + "]"}
    31  
    32  	i := -1
    33  	stderr := evalCfg.Ports[2].File
    34  	for it := hook.Iterator(); it.HasElem(); it.Next() {
    35  		i++
    36  		fn, ok := it.Elem().(Callable)
    37  		if !ok {
    38  			diag.ShowError(stderr, fmt.Errorf("hook %s[%d] must be callable", name, i))
    39  			continue
    40  		}
    41  
    42  		err := ev.Call(fn, callCfg, *evalCfg)
    43  		if err != nil {
    44  			diag.ShowError(stderr, err)
    45  		}
    46  	}
    47  }