github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/spellcheck/highlight.go (about)

     1  package spellcheck
     2  
     3  import (
     4  	"unicode"
     5  
     6  	"github.com/lmorg/murex/utils/ansi"
     7  	"github.com/lmorg/murex/utils/inject"
     8  )
     9  
    10  type highlightT struct {
    11  	start string
    12  	end   string
    13  }
    14  
    15  func (hl *highlightT) Start() []rune { return []rune(ansi.ExpandConsts(hl.start)) }
    16  func (hl *highlightT) End() []rune   { return []rune(ansi.ExpandConsts(hl.end)) }
    17  
    18  var highlight *highlightT
    19  
    20  func init() {
    21  	highlight = &highlightT{
    22  		start: "{UNDERLINE}",
    23  		end:   "{UNDEROFF}",
    24  	}
    25  }
    26  
    27  func highlighter(line *string, word []rune, highlight *highlightT) {
    28  	var (
    29  		i     int
    30  		rLast rune
    31  		r     = []rune(*line)
    32  	)
    33  
    34  	defer func() { *line = string(r) }()
    35  
    36  	for ; i < len(r); i++ {
    37  		if r[i] == word[0] {
    38  			if r[i] == word[0] &&
    39  				!(unicode.IsLetter(rLast) ||
    40  					unicode.IsDigit(rLast) ||
    41  					unicode.IsMark(rLast)) {
    42  
    43  				// first character of word found
    44  
    45  				rStart := i
    46  				for j := 1; j < len(word); j++ {
    47  					i++
    48  
    49  					switch {
    50  					case i == len(r):
    51  						// end of line reached
    52  						return
    53  
    54  					case r[i] != word[j]:
    55  						// word not matched
    56  						goto breakfor
    57  
    58  					case j+1 == len(word):
    59  						// entire word match found
    60  						if i+1 < len(r) && (unicode.IsLetter(r[i+1]) || unicode.IsMark(r[i+1]) || unicode.IsDigit(r[i+1])) {
    61  							// word is substring of a larger word
    62  
    63  						} else {
    64  							// add highlight
    65  							var err error
    66  							r, err = inject.Rune(r, highlight.End(), i+1)
    67  							if err != nil {
    68  								return
    69  							}
    70  							r, err = inject.Rune(r, highlight.Start(), rStart)
    71  							if err != nil {
    72  								return
    73  							}
    74  
    75  						}
    76  
    77  					default:
    78  						continue
    79  					}
    80  				}
    81  			breakfor:
    82  			}
    83  		}
    84  		rLast = r[i]
    85  	}
    86  }