github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/x/text/unicode/bidi/example_test.go (about) 1 // Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. 2 3 // +build ignore 4 5 package bidi_test 6 7 import ( 8 "fmt" 9 "log" 10 11 "github.com/icodeface/tls/internal/x/text/bidi" 12 ) 13 14 func foo() { 15 var sa StringAttributes 16 var p Paragraph 17 n, _ := p.SetString(s) 18 for i, o := 0, p.Ordering(); i < o.NumRuns(); i++ { 19 b := o.Run(i).Bytes() 20 21 start, end := o.Run(i).Pos() 22 for p := start; p < end; { 23 style, n := sa.StyleAt(start) 24 render() 25 p += n 26 } 27 28 } 29 } 30 31 type style int 32 33 const ( 34 styleNormal = 0 35 styleSelected = 1 << (iota - 1) 36 styleBold 37 styleItalics 38 ) 39 40 type styleRun struct { 41 end int 42 style style 43 } 44 45 func getTextWidth(text string, styleRuns []styleRun) int { 46 // simplistic way to compute the width 47 return len([]rune(text)) 48 } 49 50 // set limit and StyleRun limit for a line 51 // from text[start] and from styleRuns[styleRunStart] 52 // using Bidi.getLogicalRun(...) 53 // returns line width 54 func getLineBreak(p *bidi.Paragraph, start int, styles []styleRun) (n int) { 55 // dummy return 56 return 0 57 } 58 59 // render runs on a line sequentially, always from left to right 60 61 // prepare rendering a new line 62 func startLine(d bidi.Direction, lineWidth int) { 63 fmt.Println() 64 } 65 66 // render a run of text and advance to the right by the run width 67 // the text[start..limit-1] is always in logical order 68 func renderRun(text string, d bidi.Direction, styl style) { 69 } 70 71 // We could compute a cross-product 72 // from the style runs with the directional runs 73 // and then reorder it. 74 // Instead, here we iterate over each run type 75 // and render the intersections - 76 // with shortcuts in simple (and common) cases. 77 // renderParagraph() is the main function. 78 79 // render a directional run with 80 // (possibly) multiple style runs intersecting with it 81 func renderDirectionalRun(text string, offset int, d bidi.Direction, styles []styleRun) { 82 start, end := offset, len(text)+offset 83 // iterate over style runs 84 if run.Direction() == bidi.LeftToRight { 85 styleEnd := 0 86 for _, sr := range styles { 87 styleEnd = styleRuns[i].end 88 if start < styleEnd { 89 if styleEnd > end { 90 styleEnd = end 91 } 92 renderRun(text[start-offset:styleEnd-offset], run.Direction(), styles[i].style) 93 if styleEnd == end { 94 break 95 } 96 start = styleEnd 97 } 98 } 99 } else { 100 styleStart := 0 101 for i := len(styles) - 1; i >= 0; i-- { 102 if i > 0 { 103 styleStart = styles[i-1].end 104 } else { 105 styleStart = 0 106 } 107 if end >= styleStart { 108 if styleStart < start { 109 styleStart = start 110 } 111 renderRun(text[styleStart-offset:end-offset], run.Direction(), styles[i].style) 112 if styleStart == start { 113 break 114 } 115 end = styleStart 116 } 117 } 118 } 119 } 120 121 // the line object represents text[start..limit-1] 122 func renderLine(line *bidi.Runs, text string, offset int, styles []styleRun) { 123 if dir := line.Direction(); dir != bidi.Mixed { 124 if len(styles) == 1 { 125 renderRun(text, dir, styles[0].style) 126 } else { 127 for i := 0; i < line.NumRuns(); i++ { 128 renderDirectionalRun(text, offset, dir, styles) 129 } 130 } 131 } else { 132 // iterate over both directional and style runs 133 for i := 0; i < line.Len(); i++ { 134 run := line.Run(i) 135 start, _ := run.Pos() 136 renderDirectionalRun(text[start-offset:], start, run.Direction(), styles) 137 } 138 } 139 } 140 141 func renderParagraph(text string, d bidi.Direction, styles []styleRun, int lineWidth) { 142 var p bidi.Paragraph 143 if err := p.SetString(text, bidi.DefaultDirection(d)); err != nil { 144 log.Fatal(err) 145 } 146 147 if len(styles) == 0 { 148 styles = append(styles, []styleRun{len(text), styleNormal}) 149 } 150 151 if width := getTextWidth(text, styles); width <= lineWidth { 152 // everything fits onto one line 153 154 runs, err := p.Runs() 155 if err != nil { 156 log.Fatal(err) 157 } 158 159 // prepare rendering a new line from either left or right 160 startLine(p.Direction(), width) 161 renderLine(&runs, text, styles) 162 } else { 163 // we need to render several lines 164 165 for start, end := 0, 0; start < len(text); start = end { 166 for start >= styles[0].end { 167 styles = styles[1:] 168 } 169 end = getLineBreak(p, start, styles[startStyles:]) 170 171 runs, err := p.Line(start, end) 172 if err != nil { 173 log.Fatal(err) 174 } 175 176 startLine(p.Direction(), end-start) 177 renderLine(&runs, text[start:end], styles[startStyles:]) 178 } 179 } 180 } 181 182 func main() { 183 renderParagraph("Some Latin text...", bidi.LeftToRight, nil, 80) 184 renderParagraph("Some Hebrew text...", bidi.RightToLeft, nil, 60) 185 }