mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-04 10:57:50 +08:00
parent
d804f82350
commit
f407b94d09
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/elves/elvish/edit/tty"
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/elves/elvish/store"
|
||||
)
|
||||
|
||||
const lackEOL = "\033[7m\u23ce\033[m\n"
|
||||
|
@ -51,6 +52,8 @@ type Editor struct {
|
|||
reader *Reader
|
||||
sigs <-chan os.Signal
|
||||
histories []string
|
||||
store *store.Store
|
||||
cmdSeq int
|
||||
editorState
|
||||
}
|
||||
|
||||
|
@ -62,39 +65,102 @@ type LineRead struct {
|
|||
Err error
|
||||
}
|
||||
|
||||
func (h *history) jump(i int, line string) {
|
||||
h.current = i
|
||||
h.line = line
|
||||
}
|
||||
|
||||
func (ed *Editor) appendHistory(line string) {
|
||||
ed.histories = append(ed.histories, line)
|
||||
if ed.store != nil {
|
||||
ed.store.AddCmd(line)
|
||||
// TODO(xiaq): Report possible error
|
||||
}
|
||||
}
|
||||
|
||||
func lastHistory(histories []string, upto int, prefix string) (int, string) {
|
||||
for i := upto - 1; i >= 0; i-- {
|
||||
if strings.HasPrefix(histories[i], prefix) {
|
||||
return i, histories[i]
|
||||
}
|
||||
}
|
||||
return -1, ""
|
||||
}
|
||||
|
||||
func firstHistory(histories []string, from int, prefix string) (int, string) {
|
||||
for i := from; i < len(histories); i++ {
|
||||
if strings.HasPrefix(histories[i], prefix) {
|
||||
return i, histories[i]
|
||||
}
|
||||
}
|
||||
return -1, ""
|
||||
}
|
||||
|
||||
func (ed *Editor) prevHistory() bool {
|
||||
for i := ed.history.current - 1; i >= 0; i-- {
|
||||
if strings.HasPrefix(ed.histories[i], ed.history.prefix) {
|
||||
ed.history.current = i
|
||||
ed.history.line = ed.histories[i]
|
||||
if ed.history.current > 0 {
|
||||
// Session history
|
||||
i, line := lastHistory(ed.histories, ed.history.current, ed.history.prefix)
|
||||
if i >= 0 {
|
||||
ed.history.jump(i, line)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if ed.store != nil {
|
||||
// Persistent history
|
||||
upto := ed.cmdSeq + min(0, ed.history.current)
|
||||
i, line, err := ed.store.LastCmd(upto, ed.history.prefix)
|
||||
if err == nil {
|
||||
ed.history.jump(i-ed.cmdSeq, line)
|
||||
return true
|
||||
}
|
||||
}
|
||||
// TODO(xiaq): Errors other than ErrNoMatchingCmd should be reported
|
||||
return false
|
||||
}
|
||||
|
||||
func (ed *Editor) nextHistory() bool {
|
||||
for i := ed.history.current + 1; i < len(ed.histories); i++ {
|
||||
if strings.HasPrefix(ed.histories[i], ed.history.prefix) {
|
||||
ed.history.current = i
|
||||
ed.history.line = ed.histories[i]
|
||||
return true
|
||||
if ed.store != nil {
|
||||
// Persistent history
|
||||
if ed.history.current < -1 {
|
||||
from := ed.cmdSeq + ed.history.current + 1
|
||||
i, line, err := ed.store.FirstCmd(from, ed.history.prefix)
|
||||
if err == nil {
|
||||
ed.history.jump(i-ed.cmdSeq, line)
|
||||
return true
|
||||
}
|
||||
// TODO(xiaq): Errors other than ErrNoMatchingCmd should be reported
|
||||
}
|
||||
}
|
||||
|
||||
from := max(0, ed.history.current+1)
|
||||
i, line := firstHistory(ed.histories, from, ed.history.prefix)
|
||||
if i >= 0 {
|
||||
ed.history.jump(i, line)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NewEditor creates an Editor.
|
||||
func NewEditor(file *os.File, sigs <-chan os.Signal) *Editor {
|
||||
func NewEditor(file *os.File, sigs <-chan os.Signal, st *store.Store) *Editor {
|
||||
seq := -1
|
||||
if st != nil {
|
||||
var err error
|
||||
seq, err = st.NextCmdSeq()
|
||||
if err != nil {
|
||||
// TODO(xiaq): Also report the error
|
||||
seq = -1
|
||||
}
|
||||
}
|
||||
|
||||
return &Editor{
|
||||
file: file,
|
||||
writer: newWriter(file),
|
||||
reader: NewReader(file),
|
||||
sigs: sigs,
|
||||
store: st,
|
||||
cmdSeq: seq,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
edit/minmax.go
Normal file
15
edit/minmax.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package edit
|
||||
|
||||
func min(a, b int) int {
|
||||
if a <= b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a >= b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
10
main.go
10
main.go
|
@ -22,7 +22,7 @@ const (
|
|||
outChanLeader = "▶ "
|
||||
)
|
||||
|
||||
func newEvaler() *eval.Evaler {
|
||||
func newEvalerAndStore() (*eval.Evaler, *store.Store) {
|
||||
dataDir, err := store.EnsureDataDir()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Warning: cannot create data dir ~/.elvish")
|
||||
|
@ -36,7 +36,7 @@ func newEvaler() *eval.Evaler {
|
|||
}
|
||||
}
|
||||
|
||||
return eval.NewEvaler(st, dataDir)
|
||||
return eval.NewEvaler(st, dataDir), st
|
||||
}
|
||||
|
||||
func printError(err error) {
|
||||
|
@ -51,7 +51,7 @@ func printError(err error) {
|
|||
|
||||
// TODO(xiaq): Currently only the editor deals with signals.
|
||||
func interact() {
|
||||
ev := newEvaler()
|
||||
ev, st := newEvalerAndStore()
|
||||
datadir, err := store.EnsureDataDir()
|
||||
printError(err)
|
||||
if err == nil {
|
||||
|
@ -76,7 +76,7 @@ func interact() {
|
|||
|
||||
sigch := make(chan os.Signal, sigchSize)
|
||||
|
||||
ed := edit.NewEditor(os.Stdin, sigch)
|
||||
ed := edit.NewEditor(os.Stdin, sigch, st)
|
||||
|
||||
for {
|
||||
cmdNum++
|
||||
|
@ -111,7 +111,7 @@ func interact() {
|
|||
}
|
||||
|
||||
func script(fname string) {
|
||||
ev := newEvaler()
|
||||
ev, _ := newEvalerAndStore()
|
||||
err := ev.Source(fname)
|
||||
printError(err)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue
Block a user