github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/edit/binding_map.go (about) 1 package edit 2 3 import ( 4 "errors" 5 "sort" 6 7 "github.com/markusbkk/elvish/pkg/eval" 8 "github.com/markusbkk/elvish/pkg/eval/vals" 9 "github.com/markusbkk/elvish/pkg/parse" 10 "github.com/markusbkk/elvish/pkg/ui" 11 ) 12 13 var errValueShouldBeFn = errors.New("value should be function") 14 15 // A special Map that converts its key to ui.Key and ensures that its values 16 // satisfy eval.CallableValue. 17 type bindingsMap struct { 18 vals.Map 19 } 20 21 var emptyBindingsMap = bindingsMap{vals.EmptyMap} 22 23 // Repr returns the representation of the binding table as if it were an 24 // ordinary map keyed by strings. 25 func (bt bindingsMap) Repr(indent int) string { 26 var keys ui.Keys 27 for it := bt.Map.Iterator(); it.HasElem(); it.Next() { 28 k, _ := it.Elem() 29 keys = append(keys, k.(ui.Key)) 30 } 31 sort.Sort(keys) 32 33 builder := vals.NewMapReprBuilder(indent) 34 35 for _, k := range keys { 36 v, _ := bt.Map.Index(k) 37 builder.WritePair(parse.Quote(k.String()), indent+2, vals.Repr(v, indent+2)) 38 } 39 40 return builder.String() 41 } 42 43 // Index converts the index to ui.Key and uses the Index of the inner Map. 44 func (bt bindingsMap) Index(index interface{}) (interface{}, error) { 45 key, err := toKey(index) 46 if err != nil { 47 return nil, err 48 } 49 return vals.Index(bt.Map, key) 50 } 51 52 func (bt bindingsMap) HasKey(k interface{}) bool { 53 _, ok := bt.Map.Index(k) 54 return ok 55 } 56 57 func (bt bindingsMap) GetKey(k ui.Key) eval.Callable { 58 v, ok := bt.Map.Index(k) 59 if !ok { 60 panic("get called when key not present") 61 } 62 return v.(eval.Callable) 63 } 64 65 // Assoc converts the index to ui.Key, ensures that the value is CallableValue, 66 // uses the Assoc of the inner Map and converts the result to a BindingTable. 67 func (bt bindingsMap) Assoc(k, v interface{}) (interface{}, error) { 68 key, err := toKey(k) 69 if err != nil { 70 return nil, err 71 } 72 f, ok := v.(eval.Callable) 73 if !ok { 74 return nil, errValueShouldBeFn 75 } 76 map2 := bt.Map.Assoc(key, f) 77 return bindingsMap{map2}, nil 78 } 79 80 // Dissoc converts the key to ui.Key and calls the Dissoc method of the inner 81 // map. 82 func (bt bindingsMap) Dissoc(k interface{}) interface{} { 83 key, err := toKey(k) 84 if err != nil { 85 // Key is invalid; dissoc is no-op. 86 return bt 87 } 88 return bindingsMap{bt.Map.Dissoc(key)} 89 } 90 91 func makeBindingMap(raw vals.Map) (bindingsMap, error) { 92 converted := vals.EmptyMap 93 for it := raw.Iterator(); it.HasElem(); it.Next() { 94 k, v := it.Elem() 95 f, ok := v.(eval.Callable) 96 if !ok { 97 return emptyBindingsMap, errValueShouldBeFn 98 } 99 key, err := toKey(k) 100 if err != nil { 101 return bindingsMap{}, err 102 } 103 converted = converted.Assoc(key, f) 104 } 105 106 return bindingsMap{converted}, nil 107 }