github.com/hoop33/elvish@v0.0.0-20160801152013-6d25485beab4/edit/prompt.go (about)

     1  package edit
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"os"
     7  	"os/user"
     8  
     9  	"github.com/elves/elvish/eval"
    10  	"github.com/elves/elvish/util"
    11  )
    12  
    13  var ErrPromptMustBeStringOrFunc = errors.New("prompt must be string or function")
    14  
    15  // PromptVariable is a prompt function variable. It may be set to a String, a
    16  // Fn, or a BuiltinPrompt. It provides $le:prompt and $le:rprompt.
    17  type PromptVariable struct {
    18  	Prompt *Prompt
    19  }
    20  
    21  func (pv PromptVariable) Get() eval.Value {
    22  	// XXX Should return a proper eval.Fn
    23  	return eval.String("<prompt>")
    24  }
    25  
    26  func (pv PromptVariable) Set(v eval.Value) {
    27  	if s, ok := v.(eval.String); ok {
    28  		*pv.Prompt = BuiltinPrompt(func(*Editor) string { return string(s) })
    29  	} else if c, ok := v.(eval.Fn); ok {
    30  		*pv.Prompt = FnAsPrompt{c}
    31  	} else {
    32  		throw(ErrPromptMustBeStringOrFunc)
    33  	}
    34  }
    35  
    36  // Prompt is the interface of prompt functions.
    37  type Prompt interface {
    38  	Call(*Editor) string
    39  }
    40  
    41  // BuiltinPrompt is a trivial implementation of Prompt.
    42  type BuiltinPrompt func(*Editor) string
    43  
    44  func (bp BuiltinPrompt) Call(ed *Editor) string {
    45  	return bp(ed)
    46  }
    47  
    48  // FnAsPrompt adapts a eval.Fn to a Prompt.
    49  type FnAsPrompt struct {
    50  	eval.Fn
    51  }
    52  
    53  func (c FnAsPrompt) Call(ed *Editor) string {
    54  	in, err := makeClosedStdin()
    55  	if err != nil {
    56  		return ""
    57  	}
    58  	ports := []*eval.Port{in, &eval.Port{File: os.Stdout}, &eval.Port{File: os.Stderr}}
    59  
    60  	// XXX There is no source to pass to NewTopEvalCtx.
    61  	ec := eval.NewTopEvalCtx(ed.evaler, "[editor prompt]", "", ports)
    62  	values, err := ec.PCaptureOutput(c.Fn, nil)
    63  	if err != nil {
    64  		ed.notify("prompt function error: %v", err)
    65  		return ""
    66  	}
    67  	var b bytes.Buffer
    68  	for _, v := range values {
    69  		b.WriteString(eval.ToString(v))
    70  	}
    71  	return b.String()
    72  }
    73  
    74  func defaultPrompts() (Prompt, Prompt) {
    75  	// Make default prompts.
    76  	username := "???"
    77  	user, err := user.Current()
    78  	if err == nil {
    79  		username = user.Username
    80  	}
    81  	hostname, err := os.Hostname()
    82  	if err != nil {
    83  		hostname = "???"
    84  	}
    85  	rpromptStr := username + "@" + hostname
    86  	prompt := func(*Editor) string {
    87  		return util.Getwd() + "> "
    88  	}
    89  	rprompt := func(*Editor) string {
    90  		return rpromptStr
    91  	}
    92  	return BuiltinPrompt(prompt), BuiltinPrompt(rprompt)
    93  }