Ejemplo n.º 1
0
func (fac FnAsArgCompleter) Complete(words []string, ed *Editor) ([]*candidate, error) {
	in, err := makeClosedStdin()
	if err != nil {
		return nil, err
	}
	ports := []*eval.Port{in, &eval.Port{File: os.Stdout}, &eval.Port{File: os.Stderr}}

	wordValues := make([]eval.Value, len(words))
	for i, word := range words {
		wordValues[i] = eval.String(word)
	}

	// XXX There is no source to pass to NewTopEvalCtx.
	ec := eval.NewTopEvalCtx(ed.evaler, "[editor completer]", "", ports)
	values, err := ec.PCaptureOutput(fac.Fn, wordValues)
	if err != nil {
		ed.notify("completer error: %v", err)
		return nil, err
	}

	cands := make([]*candidate, len(values))
	for i, v := range values {
		s := eval.ToString(v)
		cands[i] = &candidate{text: s}
	}
	return cands, nil
}
Ejemplo n.º 2
0
Archivo: call.go Proyecto: zhsj/elvish
func callFnForCandidates(fn eval.FnValue, ev *eval.Evaler, args []string) ([]*candidate, error) {
	ports := []*eval.Port{eval.DevNullClosedChan, &eval.Port{File: os.Stdout}, &eval.Port{File: os.Stderr}}

	argValues := make([]eval.Value, len(args))
	for i, arg := range args {
		argValues[i] = eval.String(arg)
	}

	// XXX There is no source to pass to NewTopEvalCtx.
	ec := eval.NewTopEvalCtx(ev, "[editor completer]", "", ports)
	values, err := ec.PCaptureOutput(fn, argValues, eval.NoOpts)
	if err != nil {
		return nil, errors.New("completer error: " + err.Error())
	}

	cands := make([]*candidate, len(values))
	for i, v := range values {
		switch v := v.(type) {
		case eval.String:
			cands[i] = &candidate{text: string(v)}
		case *candidate:
			cands[i] = v
		default:
			return nil, errors.New("completer must output string or candidate")
		}
	}
	return cands, nil
}
Ejemplo n.º 3
0
func (c EvalCaller) Call(ed *Editor) {
	// Input
	devnull, err := os.Open("/dev/null")
	if err != nil {
		Logger.Println(err)
		return
	}
	defer devnull.Close()
	in := make(chan eval.Value)
	close(in)

	// Output
	rout, out, err := os.Pipe()
	if err != nil {
		Logger.Println(err)
		return
	}
	chanOut := make(chan eval.Value)

	// Goroutines to collect output.
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		rd := bufio.NewReader(rout)
		for {
			line, err := rd.ReadString('\n')
			Logger.Println("function writes bytes", line)
			if err != nil {
				break
			}
		}
		rout.Close()
		wg.Done()
	}()
	go func() {
		for v := range chanOut {
			Logger.Println("function writes Value", v.Repr())
		}
		wg.Done()
	}()

	ports := []*eval.Port{
		{File: devnull, Chan: in},
		{File: out, Chan: chanOut},
		{File: out, Chan: chanOut},
	}
	// XXX There is no source to pass to NewTopEvalCtx.
	ec := eval.NewTopEvalCtx(ed.evaler, "[editor]", "", ports)
	ex := ec.PCall(c.Caller, []eval.Value{})
	if ex != nil {
		ed.notify("function error: %s", ex.Error())
	}

	out.Close()
	close(chanOut)
	wg.Wait()

	ed.refresh(true)
}
Ejemplo n.º 4
0
Archivo: call.go Proyecto: zhsj/elvish
// CallFn calls an Fn, displaying its outputs and possible errors as editor
// notifications. It is the preferred way to call a Fn while the editor is
// active.
func (ed *Editor) CallFn(fn eval.FnValue, args ...eval.Value) {
	if b, ok := fn.(*BuiltinFn); ok {
		// Builtin function: quick path.
		b.impl(ed)
		return
	}

	rout, chanOut, ports, err := makePorts()
	if err != nil {
		return
	}

	// Goroutines to collect output.
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		rd := bufio.NewReader(rout)
		for {
			line, err := rd.ReadString('\n')
			if err != nil {
				break
			}
			ed.Notify("[bytes output] %s", line[:len(line)-1])
		}
		rout.Close()
		wg.Done()
	}()
	go func() {
		for v := range chanOut {
			ed.Notify("[value output] %s", v.Repr(eval.NoPretty))
		}
		wg.Done()
	}()

	// XXX There is no source to pass to NewTopEvalCtx.
	ec := eval.NewTopEvalCtx(ed.evaler, "[editor]", "", ports)
	ex := ec.PCall(fn, args, eval.NoOpts)
	if ex != nil {
		ed.Notify("function error: %s", ex.Error())
	}

	eval.ClosePorts(ports)
	wg.Wait()
	ed.refresh(true, true)
}
Ejemplo n.º 5
0
Archivo: call.go Proyecto: zhsj/elvish
// callFnAsPrompt calls a Fn with closed input, captures its output and convert
// the output to a slice of *styled's.
func callFnForPrompt(ed *Editor, fn eval.Fn) []*styled {
	ports := []*eval.Port{eval.DevNullClosedChan, &eval.Port{File: os.Stdout}, &eval.Port{File: os.Stderr}}

	// XXX There is no source to pass to NewTopEvalCtx.
	ec := eval.NewTopEvalCtx(ed.evaler, "[editor prompt]", "", ports)
	values, err := ec.PCaptureOutput(fn, nil, eval.NoOpts)
	if err != nil {
		ed.Notify("prompt function error: %v", err)
		return nil
	}

	var ss []*styled
	for _, v := range values {
		if s, ok := v.(*styled); ok {
			ss = append(ss, s)
		} else {
			ss = append(ss, &styled{eval.ToString(v), ""})
		}
	}
	return ss
}
Ejemplo n.º 6
0
func (c FnAsBoundFunc) Call(ed *Editor) {
	rout, chanOut, ports, err := makePorts()
	if err != nil {
		return
	}

	// Goroutines to collect output.
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		rd := bufio.NewReader(rout)
		for {
			line, err := rd.ReadString('\n')
			if err != nil {
				break
			}
			// XXX notify is not concurrency-safe.
			ed.notify("[bound fn bytes] %s", line[:len(line)-1])
		}
		rout.Close()
		wg.Done()
	}()
	go func() {
		for v := range chanOut {
			ed.notify("[bound fn value] %s", v.Repr(eval.NoPretty))
		}
		wg.Done()
	}()

	// XXX There is no source to pass to NewTopEvalCtx.
	ec := eval.NewTopEvalCtx(ed.evaler, "[editor]", "", ports)
	ex := ec.PCall(c.Fn, []eval.Value{})
	if ex != nil {
		ed.notify("function error: %s", ex.Error())
	}

	eval.ClosePorts(ports)
	wg.Wait()
	ed.refresh(true, true)
}