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

     1  package drawer4
     2  
     3  import (
     4  	"github.com/jmigpin/editor/util/fontutil"
     5  	"github.com/jmigpin/editor/util/mathutil"
     6  )
     7  
     8  type Annotations struct {
     9  	d          *Drawer
    10  	notesFFace *fontutil.FontFace
    11  }
    12  
    13  func (ann *Annotations) Init() {
    14  	size2 := ann.d.st.runeR.fface.Size * 0.70
    15  	ann.notesFFace = ann.d.st.runeR.fface.Font.FontFace2(size2)
    16  }
    17  
    18  func (ann *Annotations) Iter() {
    19  	if ann.d.Opt.Annotations.On {
    20  		if ann.d.iters.runeR.isNormal() {
    21  			ann.iter2()
    22  		}
    23  	}
    24  	if !ann.d.iterNext() {
    25  		return
    26  	}
    27  }
    28  
    29  func (ann *Annotations) iter2() {
    30  	entries := ann.d.Opt.Annotations.Entries // *mostly* ordered by offset
    31  	i := &ann.d.st.annotations.cei
    32  	q := &ann.d.st.annotations.indexQ
    33  	// add annotations up to the first entry offset, only need to check next entries with offsets smaller then the first entry (ex: function literals with inner annotations that have higher entry index, but lower offsets).
    34  	var first *Annotation
    35  	for k := *i; k < len(entries); k++ {
    36  		e := entries[k]
    37  		if e == nil {
    38  			continue
    39  		}
    40  		// past annotation
    41  		if e.Offset < ann.d.st.runeR.ri {
    42  			continue
    43  		}
    44  
    45  		if first == nil {
    46  			first = e
    47  		}
    48  
    49  		// annotation match
    50  		if e.Offset == ann.d.st.runeR.ri {
    51  			*q = append(*q, k)
    52  			if k == *i { // handled next entry
    53  				*i++
    54  				first = nil
    55  				continue
    56  			}
    57  		}
    58  
    59  		// future annotation
    60  		// Commented: need to handle next entries with earlier offsets
    61  		//if e.Offset > ann.d.st.runeR.ri {
    62  		//break
    63  		//}
    64  		// future annotation after the first entry
    65  		if e.Offset > first.Offset {
    66  			break
    67  		}
    68  	}
    69  
    70  	// add annotations after newline
    71  	if len(*q) > 0 {
    72  		switch ann.d.st.runeR.ru {
    73  		case '\n', 0: // insert annotations at newline or EOF
    74  			ann.insertAnnotations()
    75  		}
    76  	}
    77  }
    78  
    79  func (ann *Annotations) End() {}
    80  
    81  //----------
    82  
    83  func (ann *Annotations) insertAnnotations() {
    84  	tmp := ann.d.st.runeR                   // keep state
    85  	defer func() { ann.d.st.runeR = tmp }() // restore state
    86  	ann.insertAnnotations2()
    87  }
    88  
    89  func (ann *Annotations) insertAnnotations2() {
    90  	// clear at the end
    91  	defer func() { ann.d.st.annotations.indexQ = []int{} }()
    92  
    93  	// separator between content and annotation
    94  	{
    95  		pen := &ann.d.st.runeR.pen
    96  		startX := pen.X + ann.d.st.runeR.advance
    97  
    98  		//if !ann.insertSeparatorString("\t") {
    99  		//	return
   100  		//}
   101  
   102  		space := ann.d.iters.runeR.glyphAdvance(' ')
   103  		boundsMinX := mathutil.Intf1(ann.d.bounds.Min.X)
   104  		min := boundsMinX + space*(8*10)
   105  		margin := space * 10
   106  		max := ann.d.iters.runeR.maxX() - margin
   107  		if pen.X < min {
   108  			pen.X = min
   109  		}
   110  		if pen.X > max {
   111  			pen.X = max
   112  		}
   113  		if pen.X < startX {
   114  			pen.X = startX
   115  		}
   116  	}
   117  
   118  	// annotations
   119  	c := 0
   120  	for _, index := range ann.d.st.annotations.indexQ {
   121  		entry := ann.d.Opt.Annotations.Entries[index]
   122  		if entry == nil {
   123  			continue
   124  		}
   125  
   126  		// space separator between entries on the same line
   127  		c++
   128  		if c >= 2 {
   129  			if !ann.insertSeparatorString(" ") {
   130  				return
   131  			}
   132  		}
   133  
   134  		s1 := string(entry.Bytes)
   135  		if !ann.insertAnnotationString(s1, index, true) {
   136  			return
   137  		}
   138  
   139  		// entry.notes (used for arrival index)
   140  		s2 := string(entry.NotesBytes)
   141  		if !ann.insertNotesString(ann.notesFFace, s2) {
   142  			return
   143  		}
   144  	}
   145  }
   146  
   147  func (ann *Annotations) insertAnnotationString(s string, eindex int, colorizeIfIndex bool) bool {
   148  	// keep/restore color state
   149  	keep := ann.d.st.curColors
   150  	defer func() { ann.d.st.curColors = keep }()
   151  	// set colors
   152  	opt := &ann.d.Opt.Annotations
   153  	if colorizeIfIndex && eindex == opt.Selected.EntryIndex {
   154  		assignColor(&ann.d.st.curColors.fg, opt.Selected.Fg)
   155  		assignColor(&ann.d.st.curColors.bg, opt.Selected.Bg)
   156  	} else {
   157  		assignColor(&ann.d.st.curColors.fg, opt.Fg)
   158  		assignColor(&ann.d.st.curColors.bg, opt.Bg)
   159  	}
   160  
   161  	// update annotationsindexof state
   162  	ann.d.st.annotationsIndexOf.inside.on = true
   163  	ann.d.st.annotationsIndexOf.inside.ei = eindex
   164  	ann.d.st.annotationsIndexOf.inside.soffset = ann.d.st.runeR.ri
   165  	defer func() { ann.d.st.annotationsIndexOf.inside.on = false }()
   166  
   167  	return ann.d.iters.runeR.insertExtraString(s)
   168  }
   169  
   170  func (ann *Annotations) insertNotesString(fface *fontutil.FontFace, s string) bool {
   171  	// keep/restore color state
   172  	keep := ann.d.st.curColors
   173  	defer func() { ann.d.st.curColors = keep }()
   174  	// set colors
   175  	ann.d.st.curColors.fg = ann.d.fg
   176  	ann.d.st.curColors.bg = nil
   177  
   178  	// keep/restore face
   179  	keepf := ann.d.st.runeR.fface
   180  	ann.d.st.runeR.fface = fface
   181  	defer func() { ann.d.st.runeR.fface = keepf }()
   182  
   183  	return ann.d.iters.runeR.insertExtraString(" " + s)
   184  }
   185  
   186  func (ann *Annotations) insertSeparatorString(s string) bool {
   187  	// keep/restore color state
   188  	keep := ann.d.st.curColors
   189  	defer func() { ann.d.st.curColors = keep }()
   190  	// set colors
   191  	ann.d.st.curColors.fg = ann.d.fg
   192  	ann.d.st.curColors.bg = nil
   193  	return ann.d.iters.runeR.insertExtraString(s)
   194  }
   195  
   196  //----------
   197  
   198  type Annotation struct {
   199  	Offset     int
   200  	Bytes      []byte
   201  	NotesBytes []byte // used for arrival index
   202  }
   203  
   204  //----------
   205  
   206  type AnnotationsIndexOf struct {
   207  	d *Drawer
   208  }
   209  
   210  func (aio *AnnotationsIndexOf) Init() {
   211  	aio.d.st.annotationsIndexOf.eindex = -1
   212  }
   213  
   214  func (aio *AnnotationsIndexOf) Iter() {
   215  	if aio.d.st.annotationsIndexOf.inside.on {
   216  		aio.iter2()
   217  	}
   218  	_ = aio.d.iterNext()
   219  }
   220  
   221  func (aio *AnnotationsIndexOf) End() {}
   222  
   223  //----------
   224  
   225  func (aio *AnnotationsIndexOf) iter2() {
   226  	p := &aio.d.st.annotationsIndexOf.p
   227  	pb := aio.d.iters.runeR.penBounds()
   228  
   229  	// before the y start
   230  	if p.Y < pb.Min.Y {
   231  		aio.d.iterStop()
   232  		return
   233  	}
   234  	// in the line
   235  	if p.Y < pb.Max.Y {
   236  		// before the x start
   237  		if p.X < pb.Min.X {
   238  			aio.d.iterStop()
   239  			return
   240  		}
   241  		// inside
   242  		if p.X < pb.Max.X {
   243  			st := &aio.d.st.annotationsIndexOf
   244  			st.eindex = st.inside.ei
   245  			st.offset = aio.d.st.runeR.ri - st.inside.soffset
   246  			aio.d.iterStop()
   247  			return
   248  		}
   249  	}
   250  }