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