size.go (3413B)
1 package render 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 ) 8 9 // Sizer splits dynamic contents into individual segments for browseable pages. 10 type Sizer struct { 11 outputSize uint32 // maximum output for a single page. 12 // menuSize uint16 // actual menu size for the dynamic page being sized 13 memberSizes map[string]uint16 // individual byte sizes of all content to be rendered by template. 14 totalMemberSize uint32 // total byte size of all content to be rendered by template (sum of memberSizes) 15 crsrs []uint32 // byte offsets in the sink content for browseable pages indices. 16 sink string // sink symbol. 17 } 18 19 // NewSizer creates a new Sizer object with the given output size constraint. 20 func NewSizer(outputSize uint32) *Sizer { 21 return &Sizer{ 22 outputSize: outputSize, 23 memberSizes: make(map[string]uint16), 24 } 25 } 26 27 // WithMenuSize sets the size of the menu being used in the rendering context. 28 //func(szr *Sizer) WithMenuSize(menuSize uint16) *Sizer { 29 // szr.menuSize = menuSize 30 // return szr 31 //} 32 33 // Set adds a content symbol in the state it will be used by the renderer. 34 func(szr *Sizer) Set(key string, size uint16) error { 35 szr.memberSizes[key] = size 36 if size == 0 { 37 szr.sink = key 38 } 39 szr.totalMemberSize += uint32(size) 40 return nil 41 } 42 43 // Check audits whether the rendered string is within the output size constraint of the sizer. 44 func(szr *Sizer) Check(s string) (uint32, bool) { 45 l := uint32(len(s)) 46 if szr.outputSize > 0 { 47 if l > szr.outputSize { 48 Logg.Infof("sized check fails", "length", l, "sizer", szr) 49 Logg.Tracef("", "sizer contents", s) 50 return 0, false 51 } 52 l = szr.outputSize - l 53 } 54 return l, true 55 } 56 57 // String implements the String interface. 58 func(szr *Sizer) String() string { 59 // var diff uint32 60 // if szr.outputSize > 0 { 61 // diff = szr.outputSize - szr.totalMemberSize - uint32(szr.menuSize) 62 // } 63 // return fmt.Sprintf("output: %v, member: %v, menu: %v, diff: %v", szr.outputSize, szr.totalMemberSize, szr.menuSize, diff) 64 return fmt.Sprintf("output: %v, member: %v", szr.outputSize, szr.totalMemberSize) 65 } 66 67 // Size gives the byte size of content for a single symbol. 68 // 69 // Fails if the symbol has not been registered using Set 70 func(szr *Sizer) Size(s string) (uint16, error) { 71 r, ok := szr.memberSizes[s] 72 if !ok { 73 return 0, fmt.Errorf("unknown member: %s", s) 74 } 75 return r, nil 76 } 77 78 // Menusize returns the currently defined menu size. 79 //func(szr *Sizer) MenuSize() uint16 { 80 // return szr.menuSize 81 //} 82 83 // AddCursor adds a pagination cursor for the paged sink content. 84 func(szr *Sizer) AddCursor(c uint32) { 85 Logg.Debugf("Added cursor", "offset", c) 86 szr.crsrs = append(szr.crsrs, c) 87 } 88 89 // GetAt the paged symbols for the current page index. 90 // 91 // Fails if index requested is out of range. 92 func(szr *Sizer) GetAt(values map[string]string, idx uint16) (map[string]string, error) { 93 if szr.sink == "" { 94 return values, nil 95 } 96 outValues := make(map[string]string) 97 for k, v := range values { 98 Logg.Tracef("check values", "k", k, "v", v, "idx", idx, "cursors", szr.crsrs) 99 if szr.sink == k { 100 if idx >= uint16(len(szr.crsrs)) { 101 return nil, fmt.Errorf("no more values in index") 102 } 103 c := szr.crsrs[idx] 104 v = v[c:] 105 nl := strings.Index(v, "\n") 106 if nl > 0 { 107 v = v[:nl] 108 } 109 b := bytes.ReplaceAll([]byte(v), []byte{0x00}, []byte{0x0a}) 110 v = string(b) 111 } 112 outValues[k] = v 113 } 114 return outValues, nil 115 } 116 117 func(szr *Sizer) Reset() { 118 szr.crsrs = []uint32{} 119 }