github.com/elves/Elvish@v0.12.0/eval/builtin_fn_misc.go (about)

     1  package eval
     2  
     3  // Builtin functions.
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"math/rand"
     9  	"net"
    10  	"path/filepath"
    11  	"time"
    12  	"unicode/utf8"
    13  
    14  	"github.com/elves/elvish/eval/vals"
    15  	"github.com/elves/elvish/parse"
    16  )
    17  
    18  // Builtins that have not been put into their own groups go here.
    19  
    20  func init() {
    21  	addBuiltinFns(map[string]interface{}{
    22  		"nop":        nop,
    23  		"kind-of":    kindOf,
    24  		"constantly": constantly,
    25  
    26  		"resolve": resolve,
    27  
    28  		"-source": source,
    29  
    30  		// Time
    31  		"esleep": sleep,
    32  		"-time":  _time,
    33  
    34  		"-ifaddrs": _ifaddrs,
    35  	})
    36  
    37  	// For rand and randint.
    38  	rand.Seed(time.Now().UTC().UnixNano())
    39  }
    40  
    41  func nop(opts RawOptions, args ...interface{}) {
    42  	// Do nothing
    43  }
    44  
    45  func kindOf(fm *Frame, args ...interface{}) {
    46  	out := fm.ports[1].Chan
    47  	for _, a := range args {
    48  		out <- vals.Kind(a)
    49  	}
    50  }
    51  
    52  func constantly(args ...interface{}) Callable {
    53  	// XXX Repr of this fn is not right
    54  	return NewBuiltinFn(
    55  		"created by constantly",
    56  		func(fm *Frame) {
    57  			out := fm.ports[1].Chan
    58  			for _, v := range args {
    59  				out <- v
    60  			}
    61  		},
    62  	)
    63  }
    64  
    65  func resolve(fm *Frame, head string) string {
    66  	// Emulate static resolution of a command head. This needs to be kept in
    67  	// sync with (*compiler).form.
    68  
    69  	_, special := builtinSpecials[head]
    70  	if special {
    71  		return "special"
    72  	} else {
    73  		explode, ns, name := ParseVariableRef(head)
    74  		if !explode && fm.ResolveVar(ns, name+FnSuffix) != nil {
    75  			return "$" + head + FnSuffix
    76  		} else {
    77  			return "(external " + parse.Quote(head) + ")"
    78  		}
    79  	}
    80  }
    81  
    82  func source(fm *Frame, fname string) error {
    83  	path, err := filepath.Abs(fname)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	code, err := readFileUTF8(path)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	n, err := parse.Parse(fname, code)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	scriptGlobal := fm.local.static()
    96  	for name := range fm.up.static() {
    97  		scriptGlobal.set(name)
    98  	}
    99  	op, err := compile(fm.Builtin.static(),
   100  		scriptGlobal, n, NewScriptSource(fname, path, code))
   101  	if err != nil {
   102  		return err
   103  	}
   104  	return fm.Eval(op)
   105  }
   106  
   107  func readFileUTF8(fname string) (string, error) {
   108  	bytes, err := ioutil.ReadFile(fname)
   109  	if err != nil {
   110  		return "", err
   111  	}
   112  	if !utf8.Valid(bytes) {
   113  		return "", fmt.Errorf("%s: source is not valid UTF-8", fname)
   114  	}
   115  	return string(bytes), nil
   116  }
   117  
   118  func sleep(fm *Frame, t float64) error {
   119  	d := time.Duration(float64(time.Second) * t)
   120  	select {
   121  	case <-fm.Interrupts():
   122  		return ErrInterrupted
   123  	case <-time.After(d):
   124  		return nil
   125  	}
   126  }
   127  
   128  func _time(fm *Frame, f Callable) error {
   129  	t0 := time.Now()
   130  	err := f.Call(fm, NoArgs, NoOpts)
   131  	t1 := time.Now()
   132  
   133  	dt := t1.Sub(t0)
   134  	fmt.Fprintln(fm.ports[1].File, dt)
   135  
   136  	return err
   137  }
   138  
   139  func _ifaddrs(fm *Frame) error {
   140  	addrs, err := net.InterfaceAddrs()
   141  	if err != nil {
   142  		return err
   143  	}
   144  	out := fm.ports[1].Chan
   145  	for _, addr := range addrs {
   146  		out <- addr.String()
   147  	}
   148  	return nil
   149  }