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

     1  package filter
     2  
     3  import (
     4  	"strings"
     5  
     6  	"src.elv.sh/pkg/diag"
     7  	"src.elv.sh/pkg/parse"
     8  	"src.elv.sh/pkg/parse/cmpd"
     9  	"src.elv.sh/pkg/ui"
    10  )
    11  
    12  func Highlight(q string) (ui.Text, []ui.Text) {
    13  	n, _ := parseFilter(q)
    14  	w := walker{}
    15  	w.walk(n)
    16  	text := ui.StyleRegions(q, w.regions)
    17  	// TODO: Add errors.
    18  	return text, nil
    19  }
    20  
    21  type walker struct {
    22  	regions []ui.StylingRegion
    23  }
    24  
    25  func (w *walker) emit(r diag.Ranger, s ui.Styling) {
    26  	region := ui.StylingRegion{Ranging: r.Range(), Styling: s}
    27  	w.regions = append(w.regions, region)
    28  }
    29  
    30  func (w *walker) walk(n parse.Node) {
    31  	switch n := n.(type) {
    32  	case *parse.Sep:
    33  		w.walkSep(n)
    34  	case *parse.Primary:
    35  		w.walkPrimary(n)
    36  	}
    37  	for _, ch := range parse.Children(n) {
    38  		w.walk(ch)
    39  	}
    40  }
    41  
    42  func (w *walker) walkSep(n *parse.Sep) {
    43  	text := parse.SourceText(n)
    44  	trimmed := strings.TrimLeftFunc(text, parse.IsWhitespace)
    45  	if trimmed == "" {
    46  		// Whitespace; nothing to do.
    47  		return
    48  	}
    49  	// Metacharacter; style it bold.
    50  	w.emit(n, ui.Bold)
    51  }
    52  
    53  func (w *walker) walkPrimary(n *parse.Primary) {
    54  	switch n.Type {
    55  	case parse.Bareword:
    56  		// Barewords are unstyled.
    57  	case parse.SingleQuoted, parse.DoubleQuoted:
    58  		w.emit(n, ui.FgYellow)
    59  	case parse.List:
    60  		if len(n.Elements) == 0 {
    61  			w.emit(n, ui.FgRed)
    62  			return
    63  		}
    64  		headNode := n.Elements[0]
    65  		head, ok := cmpd.StringLiteral(headNode)
    66  		if !ok {
    67  			w.emit(headNode, ui.FgRed)
    68  		}
    69  		switch head {
    70  		case "re", "and", "or":
    71  			w.emit(headNode, ui.FgGreen)
    72  		default:
    73  			w.emit(headNode, ui.FgRed)
    74  		}
    75  	default:
    76  		// Unsupported primary type.
    77  		w.emit(n, ui.FgRed)
    78  	}
    79  }