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