src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/edit/highlight/highlighter.go (about)

     1  package highlight
     2  
     3  import (
     4  	"sync"
     5  
     6  	"src.elv.sh/pkg/ui"
     7  )
     8  
     9  const latesBufferSize = 128
    10  
    11  // Highlighter is a code highlighter that can deliver results asynchronously.
    12  type Highlighter struct {
    13  	cfg   Config
    14  	lates chan struct{}
    15  
    16  	cacheMutex sync.Mutex
    17  	cache      cache
    18  }
    19  
    20  type cache struct {
    21  	code       string
    22  	styledCode ui.Text
    23  	tips       []ui.Text
    24  }
    25  
    26  func NewHighlighter(cfg Config) *Highlighter {
    27  	return &Highlighter{cfg: cfg, lates: make(chan struct{}, latesBufferSize)}
    28  }
    29  
    30  // Get returns the highlighted code and static errors found in the code as tips.
    31  func (hl *Highlighter) Get(code string) (ui.Text, []ui.Text) {
    32  	hl.cacheMutex.Lock()
    33  	defer hl.cacheMutex.Unlock()
    34  	if code == hl.cache.code {
    35  		return hl.cache.styledCode, hl.cache.tips
    36  	}
    37  
    38  	lateCb := func(styledCode ui.Text) {
    39  		hl.cacheMutex.Lock()
    40  		if hl.cache.code != code {
    41  			// Late result was delivered after code has changed. Unlock and
    42  			// return.
    43  			hl.cacheMutex.Unlock()
    44  			return
    45  		}
    46  		hl.cache.styledCode = styledCode
    47  		// The channel send below might block, so unlock the state first.
    48  		hl.cacheMutex.Unlock()
    49  		hl.lates <- struct{}{}
    50  	}
    51  
    52  	styledCode, tips := highlight(code, hl.cfg, lateCb)
    53  
    54  	hl.cache = cache{code, styledCode, tips}
    55  	return styledCode, tips
    56  }
    57  
    58  // LateUpdates returns a channel for notifying late updates.
    59  func (hl *Highlighter) LateUpdates() <-chan struct{} {
    60  	return hl.lates
    61  }
    62  
    63  // InvalidateCache invalidates the cached highlighting result.
    64  func (hl *Highlighter) InvalidateCache() {
    65  	hl.cacheMutex.Lock()
    66  	defer hl.cacheMutex.Unlock()
    67  	hl.cache = cache{}
    68  }