Prompt can now be customized by modifying le:{,r}prompt.

This fixes #103.
This commit is contained in:
Qi Xiao 2016-02-23 13:24:28 +01:00
parent 9d7e5de667
commit 67e4b5df11
4 changed files with 60 additions and 24 deletions

View File

@ -29,6 +29,8 @@ type Editor struct {
store *store.Store store *store.Store
evaler *eval.Evaler evaler *eval.Evaler
cmdSeq int cmdSeq int
ps1 Prompt
rps1 Prompt
editorState editorState
} }
@ -93,6 +95,8 @@ func NewEditor(file *os.File, sigs chan os.Signal, ev *eval.Evaler, st *store.St
} }
} }
prompt, rprompt := defaultPrompts()
ed := &Editor{ ed := &Editor{
file: file, file: file,
writer: newWriter(file), writer: newWriter(file),
@ -101,6 +105,8 @@ func NewEditor(file *os.File, sigs chan os.Signal, ev *eval.Evaler, st *store.St
store: st, store: st,
evaler: ev, evaler: ev,
cmdSeq: seq, cmdSeq: seq,
ps1: prompt,
rps1: rprompt,
} }
ev.AddModule("le", makeModule(ed)) ev.AddModule("le", makeModule(ed))
return ed return ed
@ -282,7 +288,7 @@ func (ed *Editor) finishReadLine(addError func(error)) {
} }
// ReadLine reads a line interactively. // ReadLine reads a line interactively.
func (ed *Editor) ReadLine(prompt, rprompt func() string) (lr LineRead) { func (ed *Editor) ReadLine() (lr LineRead) {
ed.editorState = editorState{active: true} ed.editorState = editorState{active: true}
isExternalCh := make(chan map[string]bool, 1) isExternalCh := make(chan map[string]bool, 1)
go getIsExternal(ed.evaler, isExternalCh) go getIsExternal(ed.evaler, isExternalCh)
@ -302,8 +308,8 @@ func (ed *Editor) ReadLine(prompt, rprompt func() string) (lr LineRead) {
MainLoop: MainLoop:
for { for {
ed.prompt = prompt() ed.prompt = ed.ps1.Call(ed)
ed.rprompt = rprompt() ed.rprompt = ed.rps1.Call(ed)
err := ed.refresh(false, true) err := ed.refresh(false, true)
if err != nil { if err != nil {

View File

@ -39,6 +39,9 @@ func makeModule(ed *Editor) eval.Namespace {
ns["binding"] = eval.NewRoVariable(binding) ns["binding"] = eval.NewRoVariable(binding)
ns["prompt"] = PromptVariable{&ed.ps1}
ns["rprompt"] = PromptVariable{&ed.rps1}
return ns return ns
} }

View File

@ -2,11 +2,36 @@ package edit
import ( import (
"bytes" "bytes"
"errors"
"os" "os"
"os/user"
"github.com/elves/elvish/eval" "github.com/elves/elvish/eval"
"github.com/elves/elvish/util"
) )
var ErrPromptMustBeStringOrFunc = errors.New("prompt must be string or function")
// PromptVariable implements $le:prompt and $le:rprompt.
type PromptVariable struct {
Prompt *Prompt
}
func (pv PromptVariable) Get() eval.Value {
// XXX Should return a proper eval.Caller
return eval.String("<prompt>")
}
func (pv PromptVariable) Set(v eval.Value) {
if s, ok := v.(eval.String); ok {
*pv.Prompt = BuiltinPrompt(func(*Editor) string { return string(s) })
} else if c, ok := v.(eval.Caller); ok {
*pv.Prompt = CallerPrompt{c}
} else {
throw(ErrPromptMustBeStringOrFunc)
}
}
// Prompt is the interface of prompt functions. // Prompt is the interface of prompt functions.
type Prompt interface { type Prompt interface {
Call(*Editor) string Call(*Editor) string
@ -29,7 +54,7 @@ func (c CallerPrompt) Call(ed *Editor) string {
if err != nil { if err != nil {
return "" return ""
} }
ports := []*eval.Port{in, nil, &eval.Port{File: os.Stderr}} ports := []*eval.Port{in, &eval.Port{File: os.Stdout}, &eval.Port{File: os.Stderr}}
// XXX There is no source to pass to NewTopEvalCtx. // XXX There is no source to pass to NewTopEvalCtx.
ec := eval.NewTopEvalCtx(ed.evaler, "[editor prompt]", "", ports) ec := eval.NewTopEvalCtx(ed.evaler, "[editor prompt]", "", ports)
@ -44,3 +69,24 @@ func (c CallerPrompt) Call(ed *Editor) string {
} }
return b.String() return b.String()
} }
func defaultPrompts() (Prompt, Prompt) {
// Make default prompts.
username := "???"
user, err := user.Current()
if err == nil {
username = user.Username
}
hostname, err := os.Hostname()
if err != nil {
hostname = "???"
}
rpromptStr := username + "@" + hostname
prompt := func(*Editor) string {
return util.Getwd() + "> "
}
rprompt := func(*Editor) string {
return rpromptStr
}
return BuiltinPrompt(prompt), BuiltinPrompt(rprompt)
}

View File

@ -8,7 +8,6 @@ import (
"io" "io"
"os" "os"
"os/signal" "os/signal"
"os/user"
"syscall" "syscall"
"time" "time"
@ -127,27 +126,9 @@ func interact(ev *eval.Evaler, st *store.Store) {
} }
} }
// Build prompt and rprompt.
username := "???"
user, err := user.Current()
if err == nil {
username = user.Username
}
hostname, err := os.Hostname()
if err != nil {
hostname = "???"
}
rpromptStr := username + "@" + hostname
prompt := func() string {
return util.Getwd() + "> "
}
rprompt := func() string {
return rpromptStr
}
// Build readLine function. // Build readLine function.
readLine := func() edit.LineRead { readLine := func() edit.LineRead {
return ed.ReadLine(prompt, rprompt) return ed.ReadLine()
} }
cooldown := time.Second cooldown := time.Second