edit: Default binding is now set in Elvish script.

This commit is contained in:
Qi Xiao 2018-01-03 07:27:34 +00:00
parent 68db7fe99c
commit 837f124f13
16 changed files with 138 additions and 199 deletions

View File

@ -1,4 +0,0 @@
package edit
const bindingElv = `
`

View File

@ -29,21 +29,6 @@ var _ = registerBuiltins(modeCompletion, map[string]func(*Editor){
"default": complDefault,
})
func init() {
registerBindings(modeCompletion, modeCompletion, map[ui.Key]string{
{ui.Up, 0}: "up",
{ui.Down, 0}: "down",
{ui.Tab, 0}: "down-cycle",
{ui.Tab, ui.Shift}: "up-cycle",
{ui.Left, 0}: "left",
{ui.Right, 0}: "right",
{ui.Enter, 0}: "accept",
{'F', ui.Ctrl}: "trigger-filter",
{'[', ui.Ctrl}: "insert:start",
ui.Default: "default",
})
}
type completion struct {
complSpec
completer string

View File

@ -146,8 +146,10 @@ func NewEditor(in *os.File, out *os.File, sigs chan os.Signal, ev *eval.Evaler)
ev.Editor = ed
installModules(ev.Builtin, ed)
ev.InstallBundled("binding", bindingElv)
ev.SourceText("[editor]", "use binding")
err = ev.SourceText("[editor]", "use binding; binding:install")
if err != nil {
fmt.Fprintln(out, "Failed to load default binding:", err)
}
return ed
}

View File

@ -30,19 +30,24 @@ func TestReadLine(t *testing.T) {
}
defer master.Close()
defer tty.Close()
// Continually consume tty outputs so that the editor is not blocked on
// writing.
var outputs []byte
go func() {
var buf [64]byte
var buf [256]byte
for {
_, err := master.Read(buf[:])
nr, err := master.Read(buf[:])
if err != nil {
break
}
outputs = append(outputs, buf[:nr]...)
}
}()
ev := eval.NewEvaler()
// XXX: Needed for "use" to work.
ev.SetLibDir("/non/exist/ent")
defer ev.Close()
for _, test := range readLineTests {
@ -73,7 +78,9 @@ func TestReadLine(t *testing.T) {
t.Errorf("ReadLine() => error %v (input %q)", err, test.input)
case <-time.After(readLineTimeout):
t.Errorf("ReadLine() timed out (input %q)", test.input)
t.Log("\n" + sys.DumpStack())
t.Log("Stack trace: \n" + sys.DumpStack())
t.Logf("Terminal output: %q", outputs)
t.FailNow()
}
}
}

View File

@ -17,14 +17,6 @@ var _ = registerBuiltins(modeHistoryListing, map[string]func(*Editor){
"toggle-case-sensitivity": histlistToggleCaseSensitivity,
})
func init() {
registerBindings(modeHistoryListing, modeHistoryListing,
map[ui.Key]string{
{'G', ui.Ctrl}: "toggle-case-sensitivity",
{'D', ui.Ctrl}: "toggle-dedup",
})
}
// ErrStoreOffline is thrown when an operation requires the storage backend, but
// it is offline.
var ErrStoreOffline = errors.New("store offline")

View File

@ -22,16 +22,6 @@ var _ = registerBuiltins("history", map[string]func(*Editor){
"default": wrapHistoryBuiltin(historyDefault),
})
func init() {
registerBindings(modeHistory, "history", map[ui.Key]string{
{ui.Up, 0}: "up",
{ui.Down, 0}: "down-or-quit",
{'[', ui.Ctrl}: "insert:start",
{'R', ui.Ctrl}: "switch-to-histlist",
ui.Default: "default",
})
}
type hist struct {
*history.Walker
}

View File

@ -54,66 +54,6 @@ var (
})
)
func init() {
registerBindings(modeInsert, "", map[ui.Key]string{
// Moving.
{ui.Left, 0}: "move-dot-left",
{ui.Right, 0}: "move-dot-right",
{ui.Up, ui.Alt}: "move-dot-up",
{ui.Down, ui.Alt}: "move-dot-down",
{ui.Left, ui.Ctrl}: "move-dot-left-word",
{ui.Right, ui.Ctrl}: "move-dot-right-word",
{'b', ui.Alt}: "move-dot-left-word",
{'f', ui.Alt}: "move-dot-right-word",
{ui.Home, 0}: "move-dot-sol",
{ui.End, 0}: "move-dot-eol",
// Killing.
{'U', ui.Ctrl}: "kill-line-left",
{'K', ui.Ctrl}: "kill-line-right",
{'W', ui.Ctrl}: "kill-word-left",
{ui.Backspace, 0}: "kill-rune-left",
{'H', ui.Ctrl}: "kill-rune-left", // Some terminal send ^H on backspace
{ui.Delete, 0}: "kill-rune-right",
// Inserting.
{'.', ui.Alt}: "insert-last-word",
{ui.Enter, ui.Alt}: "insert-key",
// Controls.
{ui.Enter, 0}: "smart-enter",
{'D', ui.Ctrl}: "return-eof",
{ui.F2, 0}: "toggle-quote-paste",
// Other modes.
// ui.Key{'[', ui.Ctrl}: "command-start",
{ui.Tab, 0}: "completion:smart-start",
{ui.Up, 0}: "history:start",
{ui.Down, 0}: "end-of-history",
{'N', ui.Ctrl}: "navigation:start",
{'R', ui.Ctrl}: "histlist:start",
{'1', ui.Alt}: "lastcmd:start",
{'L', ui.Ctrl}: "location:start",
{'V', ui.Ctrl}: "insert-raw",
ui.Default: "insert:default",
})
registerBindings(modeCommand, "", map[ui.Key]string{
// Moving.
{'h', 0}: "move-dot-left",
{'l', 0}: "move-dot-right",
{'k', 0}: "move-dot-up",
{'j', 0}: "move-dot-down",
{'b', 0}: "move-dot-left-word",
{'w', 0}: "move-dot-right-word",
{'0', 0}: "move-dot-sol",
{'$', 0}: "move-dot-eol",
// Killing.
{'x', 0}: "kill-rune-right",
{'D', 0}: "kill-line-right",
// Controls.
{'i', 0}: "insert:start",
ui.Default: "command:default",
})
}
type insert struct {
quotePaste bool
// The number of consecutive key inserts. Used for abbreviation expansion.

View File

@ -15,12 +15,6 @@ var _ = registerBuiltins(modeLastCmd, map[string]func(*Editor){
"alt-default": lastcmdAltDefault,
})
func init() {
registerBindings(modeLastCmd, modeLastCmd, map[ui.Key]string{
ui.Default: "alt-default",
})
}
type lastcmdEntry struct {
i int
s string

View File

@ -29,22 +29,6 @@ var _ = registerBuiltins(modeListing, map[string]func(*Editor){
"default": func(ed *Editor) { getListing(ed).defaultBinding(ed) },
})
func init() {
registerBindings(modeListing, modeListing, map[ui.Key]string{
{ui.Up, 0}: "up",
{ui.PageUp, 0}: "page-up",
{ui.Down, 0}: "down",
{ui.PageDown, 0}: "page-down",
{ui.Tab, 0}: "down-cycle",
{ui.Tab, ui.Shift}: "up-cycle",
{ui.Backspace, 0}: "backspace",
{ui.Enter, 0}: "accept-close",
{ui.Enter, ui.Alt}: "accept",
ui.Default: "default",
{'[', ui.Ctrl}: "insert:start",
})
}
// listing implements a listing mode that supports the notion of selecting an
// entry and filtering entries.
type listing struct {

View File

@ -23,10 +23,6 @@ var _ = registerBuiltins(modeLocation, map[string]func(*Editor){
"start": locStart,
})
func init() {
registerBindings(modeLocation, modeLocation, map[ui.Key]string{})
}
// PinnedScore is a special value of Score in storedefs.Dir to represent that the
// directory is pinned.
var PinnedScore = math.Inf(1)

View File

@ -6,8 +6,7 @@ import (
"github.com/elves/elvish/eval/vartypes"
)
// Names of modes, used for subnamespaces of edit: and name of binding table in
// $edit:binding.
// Names of modes, used for subnamespaces of edit:.
const (
modeInsert = "insert"
modeRawInsert = "raw-insert"

View File

@ -40,10 +40,6 @@ var _ = registerBuiltins(modeNarrow, map[string]func(*Editor){
"default": func(ed *Editor) { getNarrow(ed).defaultBinding(ed) },
})
func init() {
registerBindings(modeNarrow, modeNarrow, nil)
}
// narrow implements a listing mode that supports the notion of selecting an
// entry and filtering entries.
type narrow struct {

View File

@ -37,25 +37,6 @@ var _ = registerBuiltins(modeNavigation, map[string]func(*Editor){
"default": navDefault,
})
func init() {
registerBindings(modeNavigation, modeNavigation, map[ui.Key]string{
{ui.Up, 0}: "up",
{ui.Down, 0}: "down",
{ui.PageUp, 0}: "page-up",
{ui.PageDown, 0}: "page-down",
{ui.Left, 0}: "left",
{ui.Right, 0}: "right",
{ui.Up, ui.Alt}: "file-preview-up",
{ui.Down, ui.Alt}: "file-preview-down",
{ui.Enter, ui.Alt}: "insert-selected",
{ui.Enter, 0}: "insert-selected-and-quit",
{'H', ui.Ctrl}: "trigger-shown-hidden",
{'F', ui.Ctrl}: "trigger-filter",
{'[', ui.Ctrl}: "insert:start",
ui.Default: "default",
})
}
type navigation struct {
current *navColumn
parent *navColumn

View File

@ -2,15 +2,10 @@ package edit
import (
"errors"
"fmt"
"os"
"strings"
"github.com/elves/elvish/edit/ui"
"github.com/elves/elvish/eval"
"github.com/elves/elvish/eval/types"
"github.com/elves/elvish/eval/vartypes"
"github.com/xiaq/persistent/hashmap"
)
// This file contains several "registries", data structure that are written
@ -67,49 +62,12 @@ func makeNsFromBuiltins(builtins map[string]*BuiltinFn) eval.Ns {
return ns
}
var keyBindings = map[string]map[ui.Key]eval.Fn{}
// registerBindings registers default bindings for a mode to initialize the
// global keyBindings map. Builtin names are resolved in the defaultMod
// subnamespace using information from builtinMaps. It should be called in init
// functions.
func registerBindings(
mt string, defaultMod string, bindingData map[ui.Key]string) struct{} {
if _, ok := keyBindings[mt]; !ok {
keyBindings[mt] = map[ui.Key]eval.Fn{}
}
for key, fullName := range bindingData {
// break fullName into mod and name.
var mod, name string
nameParts := strings.SplitN(fullName, ":", 2)
if len(nameParts) == 2 {
mod, name = nameParts[0], nameParts[1]
} else {
mod, name = defaultMod, nameParts[0]
}
if m, ok := builtinMaps[mod]; ok {
if builtin, ok := m[name]; ok {
keyBindings[mt][key] = builtin
} else {
fmt.Fprintln(os.Stderr, "Internal warning: no such builtin", name, "in mod", mod)
}
} else {
fmt.Fprintln(os.Stderr, "Internal warning: no such mod:", mod)
}
}
return struct{}{}
}
func makeBindings() map[string]vartypes.Variable {
bindings := make(map[string]vartypes.Variable)
for mode, binding := range keyBindings {
bindingValue := hashmap.Empty
for key, fn := range binding {
bindingValue = bindingValue.Assoc(key, fn)
}
bindings := map[string]vartypes.Variable{}
// XXX This abuses the builtin registry to get a list of mode names
for mode := range builtinMaps {
bindings[mode] = vartypes.NewValidatedPtrVariable(
BindingTable{types.NewMap(bindingValue)}, shouldBeBindingTable)
BindingTable{types.EmptyMap}, shouldBeBindingTable)
}
return bindings
}

118
eval/bundled/binding.elv.go Normal file
View File

@ -0,0 +1,118 @@
package bundled
const bindingElv = `
fn install {
edit:insert:binding = (edit:binding-table [
&Default= $edit:insert:default~
&F2= $edit:toggle-quote-paste~
&Up= $edit:history:start~
&Down= $edit:end-of-history~
&Right= $edit:move-dot-right~
&Left= $edit:move-dot-left~
&Home= $edit:move-dot-sol~
&Delete= $edit:kill-rune-right~
&End= $edit:move-dot-eol~
&Tab= $edit:completion:smart-start~
&Enter= $edit:smart-enter~
&Backspace= $edit:kill-rune-left~
&Alt-Up= $edit:move-dot-up~
&Alt-Down= $edit:move-dot-down~
&Alt-Enter= $edit:insert-key~
&Alt-.= $edit:insert-last-word~
&Alt-1= $edit:lastcmd:start~
&Alt-b= $edit:move-dot-left-word~
&Alt-f= $edit:move-dot-right-word~
&Ctrl-Right= $edit:move-dot-right-word~
&Ctrl-Left= $edit:move-dot-left-word~
&Ctrl-D= $edit:return-eof~
&Ctrl-H= $edit:kill-rune-left~
&Ctrl-K= $edit:kill-line-right~
&Ctrl-L= $edit:location:start~
&Ctrl-N= $edit:navigation:start~
&Ctrl-R= $edit:histlist:start~
&Ctrl-U= $edit:kill-line-left~
&Ctrl-V= $edit:insert-raw~
&Ctrl-W= $edit:kill-word-left~
])
edit:command:binding = (edit:binding-table [
&Default= $edit:command:default~
&'$'= $edit:move-dot-eol~
&0= $edit:move-dot-sol~
&D= $edit:kill-line-right~
&b= $edit:move-dot-left-word~
&h= $edit:move-dot-left~
&i= $edit:insert:start~
&j= $edit:move-dot-down~
&k= $edit:move-dot-up~
&l= $edit:move-dot-right~
&w= $edit:move-dot-right-word~
&x= $edit:kill-rune-right~
])
edit:history:binding = (edit:binding-table [
&Default= $edit:history:default~
&Up= $edit:history:up~
&Down= $edit:history:down-or-quit~
&Ctrl-R= $edit:history:switch-to-histlist~
&'Ctrl-['= $edit:insert:start~
])
edit:completion:binding = (edit:binding-table [
&Default= $edit:completion:default~
&Up= $edit:completion:up~
&Down= $edit:completion:down~
&Right= $edit:completion:right~
&Left= $edit:completion:left~
&Tab= $edit:completion:down-cycle~
&Enter= $edit:completion:accept~
&Shift-Tab= $edit:completion:up-cycle~
&Ctrl-F= $edit:completion:trigger-filter~
&'Ctrl-['= $edit:insert:start~
])
edit:listing:binding = (edit:binding-table [
&Default= $edit:listing:default~
&Up= $edit:listing:up~
&Down= $edit:listing:down~
&PageUp= $edit:listing:page-up~
&PageDown= $edit:listing:page-down~
&Tab= $edit:listing:down-cycle~
&Enter= $edit:listing:accept-close~
&Backspace= $edit:listing:backspace~
&Shift-Tab= $edit:listing:up-cycle~
&Alt-Enter= $edit:listing:accept~
&'Ctrl-['= $edit:insert:start~
])
edit:histlist:binding = (edit:binding-table [
&Ctrl-D= $edit:histlist:toggle-dedup~
&Ctrl-G= $edit:histlist:toggle-case-sensitivity~
])
edit:location:binding = (edit:binding-table [&])
edit:lastcmd:binding = (edit:binding-table [
&Default= $edit:lastcmd:alt-default~
])
edit:navigation:binding = (edit:binding-table [
&Default= $edit:navigation:default~
&Up= $edit:navigation:up~
&Down= $edit:navigation:down~
&Right= $edit:navigation:right~
&Left= $edit:navigation:left~
&PageUp= $edit:navigation:page-up~
&PageDown= $edit:navigation:page-down~
&Enter= $edit:navigation:insert-selected-and-quit~
&Alt-Up= $edit:navigation:file-preview-up~
&Alt-Down= $edit:navigation:file-preview-down~
&Alt-Enter= $edit:navigation:insert-selected~
&Ctrl-F= $edit:navigation:trigger-filter~
&Ctrl-H= $edit:navigation:trigger-shown-hidden~
&'Ctrl-['= $edit:insert:start~
])
edit:narrow:binding = (edit:binding-table [&])
}
`

View File

@ -4,6 +4,7 @@ package bundled
// Get returns a map of bundled modules.
func Get() map[string]string {
return map[string]string{
"binding": bindingElv,
"epm": epmElv,
"narrow": narrowElv,
"readline-binding": readlineBindingElv,