github.com/jmigpin/editor@v1.6.0/util/drawutil/drawer4/linewrap.go (about)

     1  package drawer4
     2  
     3  type LineWrap struct {
     4  	d *Drawer
     5  }
     6  
     7  func (lw *LineWrap) Init() {}
     8  
     9  func (lw *LineWrap) Iter() {
    10  	if lw.d.Opt.LineWrap.On && lw.d.iters.runeR.isNormal() {
    11  		// pen.x>startpen.x forces at least one rune on line start
    12  		stR := &lw.d.st.runeR
    13  		penXAdv := stR.pen.X + stR.advance
    14  		maxX := lw.d.iters.runeR.maxX()
    15  		if penXAdv > maxX && stR.pen.X > lw.d.iters.runeR.startingPen().X {
    16  			lw.d.st.lineWrap.wrapping = true
    17  
    18  			if !lw.preLineWrap() {
    19  				return
    20  			}
    21  
    22  			lw.d.iters.line.newLineKeepAdv()
    23  
    24  			if !lw.postLineWrap() {
    25  				return
    26  			}
    27  		}
    28  	}
    29  
    30  	// after postlinewrap to allow indent to be added
    31  	if lw.d.st.lineWrap.wrapping {
    32  		if !lw.insertWrapRune() {
    33  			return
    34  		}
    35  		// recalc (tab) advance after possible insertions
    36  		lw.d.st.runeR.advance = lw.d.iters.runeR.tabbedGlyphAdvance(lw.d.st.runeR.ru)
    37  	}
    38  	lw.d.st.lineWrap.wrapping = false
    39  
    40  	if !lw.d.iterNext() {
    41  		return
    42  	}
    43  }
    44  
    45  func (lw *LineWrap) End() {}
    46  
    47  //----------
    48  
    49  func (lw *LineWrap) preLineWrap() bool {
    50  	// draw only the background, use space rune
    51  	ru := lw.d.st.runeR.ru // keep state
    52  	defer func() { lw.d.st.runeR.ru = ru }()
    53  	lw.d.st.runeR.ru = ' ' // draw only the background, use space rune
    54  
    55  	cc := lw.d.st.curColors
    56  	defer func() { lw.d.st.curColors = cc }()
    57  	assignColor(&lw.d.st.curColors.bg, lw.d.Opt.LineWrap.Bg)
    58  
    59  	lw.d.st.lineWrap.preLineWrap = true
    60  	defer func() { lw.d.st.lineWrap.preLineWrap = false }()
    61  
    62  	// current rune advance covers the space to the border
    63  	return lw.d.iterNextExtra()
    64  }
    65  
    66  func (lw *LineWrap) postLineWrap() bool {
    67  	// allow post line detection (this rune is not to be drawn)
    68  	ru := lw.d.st.runeR.ru // keep state
    69  	defer func() { lw.d.st.runeR.ru = ru }()
    70  	lw.d.st.runeR.ru = noDrawRune
    71  
    72  	lw.d.st.lineWrap.postLineWrap = true
    73  	defer func() { lw.d.st.lineWrap.postLineWrap = false }()
    74  
    75  	return lw.d.iterNextExtra()
    76  }
    77  
    78  func (lw *LineWrap) insertWrapRune() bool {
    79  	// keep state
    80  	rr := lw.d.st.runeR
    81  	defer func() {
    82  		penX := lw.d.st.runeR.pen.X
    83  		lw.d.st.runeR = rr
    84  		lw.d.st.runeR.pen.X = penX // use the new penX
    85  	}()
    86  
    87  	cc := lw.d.st.curColors // keep state
    88  	defer func() { lw.d.st.curColors = cc }()
    89  	assignColor(&lw.d.st.curColors.fg, lw.d.Opt.LineWrap.Fg)
    90  	assignColor(&lw.d.st.curColors.bg, lw.d.Opt.LineWrap.Bg)
    91  
    92  	s := string(WrapLineRune)
    93  	return lw.d.iters.runeR.insertExtraString(s)
    94  }
    95  
    96  var WrapLineRune = rune('←') // positioned at the start of wrapped line (left)