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 }