// Package edit implements the line editor for Elvish. // // The line editor is based on the cli package, which implements a general, // Elvish-agnostic line editor, and multiple "addon" packages. This package // glues them together and provides Elvish bindings for them.
package edit import ( ) // Editor is the interactive line editor for Elvish. type Editor struct { app cli.App ns *eval.Ns excMutex sync.RWMutex excList vals.List // Maybe move this to another type that represents the REPL cycle as a whole, not just the // read/edit portion represented by the Editor type. AfterCommand []func(src parse.Source, duration float64, err error) } // An interface that wraps notifyf and notifyError. It is only implemented by // the *Editor type; functions may take a notifier instead of *Editor argument // to make it clear that they do not depend on other parts of *Editor. type notifier interface { notifyf(format string, args ...interface{}) notifyError(ctx string, e error) } // NewEditor creates a new editor. The TTY is used for input and output. The // Evaler is used for syntax highlighting, completion, and calling callbacks. // The Store is used for saving and retrieving command and directory history. func ( cli.TTY, *eval.Evaler, store.Store) *Editor { // Declare the Editor with a nil App first; some initialization functions // require a notifier as an argument, but does not use it immediately. := &Editor{excList: vals.EmptyList} := eval.NsBuilder{} := cli.AppSpec{TTY: } , := newHistStore() if != nil { // TODO(xiaq): Report the error. } initHighlighter(&, ) initMaxHeight(&, ) initReadlineHooks(&, , ) initAddCmdFilters(&, , , ) initGlobalBindings(&, , , ) initInsertAPI(&, , , ) initPrompts(&, , , ) .app = cli.NewApp() initExceptionsAPI(, ) initVarsAPI(, ) initCommandAPI(, , ) initListings(, , , , ) initNavigation(, , ) initCompletion(, , ) initHistWalk(, , , ) initInstant(, , ) initMinibuf(, , ) initRepl(, , ) initBufferBuiltins(.app, ) initTTYBuiltins(.app, , ) initMiscBuiltins(.app, ) initStateAPI(.app, ) initStoreAPI(.app, , ) .ns = .Ns() initElvishState(, .ns) return } //elvdoc:var exceptions // // A list of exceptions thrown from callbacks such as prompts. Useful for // examining tracebacks and other metadata. func ( *Editor, eval.NsBuilder) { .Add("exceptions", vars.FromPtrWithMutex(&.excList, &.excMutex)) } // Initialize the `edit` module by executing the pre-defined Elvish code for the module. func ( *eval.Evaler, *eval.Ns) { := parse.Source{Name: "[RC file]", Code: elvInit} := .Eval(, eval.EvalCfg{Global: }) if != nil { panic() } } // ReadCode reads input from the user. func ( *Editor) () (string, error) { return .app.ReadCode() } // RunAfterCommandHooks runs callbacks involving the interactive completion of a command line. func ( *Editor) ( parse.Source, float64, error) { for , := range .AfterCommand { (, , ) } } // Ns returns a namespace for manipulating the editor from Elvish code. // // See https://elv.sh/ref/edit.html for the Elvish API. func ( *Editor) () *eval.Ns { return .ns } func ( *Editor) ( string, ...interface{}) { .app.Notify(fmt.Sprintf(, ...)) } func ( *Editor) ( string, error) { if , := .(eval.Exception); { .excMutex.Lock() defer .excMutex.Unlock() .excList = .excList.Cons() .notifyf("[%v error] %v\n"+ `see stack trace with "show $edit:exceptions[%d]"`, , , .excList.Len()-1) } else { .notifyf("[%v error] %v", , ) } }