github.com/jmigpin/editor@v1.6.0/util/drawutil/drawer4/parenthesishighlight.go (about) 1 package drawer4 2 3 import "github.com/jmigpin/editor/util/iout/iorw" 4 5 func updateParenthesisHighlight(d *Drawer) { 6 if !d.Opt.ParenthesisHighlight.On { 7 d.Opt.ParenthesisHighlight.Group.Ops = nil 8 return 9 } 10 11 if d.opt.parenthesisH.updated { 12 return 13 } 14 d.opt.parenthesisH.updated = true 15 16 d.Opt.ParenthesisHighlight.Group.Ops = parenthesisHOps(d, 5000) 17 } 18 19 //---------- 20 21 func parenthesisHOps(d *Drawer, maxDist int) []*ColorizeOp { 22 if !d.Opt.Cursor.On { 23 return nil 24 } 25 26 pairs := []rune{'{', '}', '(', ')', '[', ']'} 27 ci := d.opt.cursor.offset 28 pi, ok := parenthesisFindPair(d, pairs, ci) 29 if !ok { 30 // try match the previous parenthesis 31 ci-- 32 if ci < 0 { 33 return nil 34 } 35 pi, ok = parenthesisFindPair(d, pairs, ci) 36 if !ok { 37 return nil 38 } 39 } 40 41 // assign open/close parenthesis 42 var open, close rune 43 isOpen := pi%2 == 0 44 var nextRune func() (rune, int, error) 45 if isOpen { 46 open, close = pairs[pi], pairs[pi+1] 47 ri := ci + len(string(open)) 48 nextRune = func() (rune, int, error) { 49 ru, size, err := iorw.ReadRuneAt(d.reader, ri) 50 if err != nil { 51 return 0, 0, err 52 } 53 ri2 := ri 54 ri += size 55 return ru, ri2, nil 56 } 57 } else { 58 open, close = pairs[pi], pairs[pi-1] 59 ri := ci 60 nextRune = func() (rune, int, error) { 61 ru, size, err := iorw.ReadLastRuneAt(d.reader, ri) 62 if err != nil { 63 return 0, 0, err 64 } 65 ri -= size 66 return ru, ri, nil 67 } 68 } 69 70 // colorize open 71 op1 := &ColorizeOp{ 72 Offset: ci, 73 Fg: d.Opt.ParenthesisHighlight.Fg, 74 Bg: d.Opt.ParenthesisHighlight.Bg, 75 } 76 op2 := &ColorizeOp{Offset: ci + len(string(open))} 77 var ops []*ColorizeOp 78 ops = append(ops, op1, op2) 79 80 // find parenthesis 81 match := 0 82 for i := 0; i < maxDist; i++ { 83 ru, ri, err := nextRune() 84 if err != nil { 85 break 86 } 87 if ru == open { 88 match++ 89 } else if ru == close { 90 if match > 0 { 91 match-- 92 } else { 93 // colorize close 94 op1 := &ColorizeOp{ 95 Offset: ri, 96 Fg: d.Opt.ParenthesisHighlight.Fg, 97 Bg: d.Opt.ParenthesisHighlight.Bg, 98 } 99 op2 := &ColorizeOp{Offset: ri + len(string(close))} 100 ops = append(ops, op1, op2) 101 if !isOpen { 102 // invert order 103 l := len(ops) 104 ops[l-4], ops[l-2] = ops[l-2], ops[l-4] 105 ops[l-3], ops[l-1] = ops[l-1], ops[l-3] 106 } 107 break 108 } 109 } 110 } 111 112 return ops 113 } 114 115 func parenthesisFindPair(d *Drawer, pairs []rune, ci int) (int, bool) { 116 // read current rune 117 cru, _, err := iorw.ReadRuneAt(d.reader, ci) 118 if err != nil { 119 return 0, false 120 } 121 122 // find parenthesis type 123 var pi int 124 for ; pi < len(pairs); pi++ { 125 if pairs[pi] == cru { 126 break 127 } 128 } 129 return pi, pi < len(pairs) 130 }