github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/edit/highlight/emitter.go (about)

     1  package highlight
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/u-root/u-root/cmds/core/elvish/edit/ui"
     7  	"github.com/u-root/u-root/cmds/core/elvish/eval"
     8  	"github.com/u-root/u-root/cmds/core/elvish/parse"
     9  )
    10  
    11  type Emitter struct {
    12  	GoodFormHead func(string) bool
    13  	AddStyling   func(begin, end int, style string)
    14  }
    15  
    16  func (e *Emitter) EmitAll(n parse.Node) {
    17  	switch n := n.(type) {
    18  	case *parse.Form:
    19  		e.form(n)
    20  	case *parse.Primary:
    21  		e.primary(n)
    22  	case *parse.Sep:
    23  		e.sep(n)
    24  	}
    25  	for _, child := range n.Children() {
    26  		e.EmitAll(child)
    27  	}
    28  }
    29  
    30  func (e *Emitter) form(n *parse.Form) {
    31  	for _, an := range n.Assignments {
    32  		if an.Left != nil && an.Left.Head != nil {
    33  			v := an.Left.Head
    34  			e.AddStyling(v.Begin(), v.End(), styleForGoodVariable.String())
    35  		}
    36  	}
    37  	for _, cn := range n.Vars {
    38  		if len(cn.Indexings) > 0 && cn.Indexings[0].Head != nil {
    39  			v := cn.Indexings[0].Head
    40  			e.AddStyling(v.Begin(), v.End(), styleForGoodVariable.String())
    41  		}
    42  	}
    43  	if n.Head != nil {
    44  		e.formHead(n.Head)
    45  	}
    46  }
    47  
    48  func (e *Emitter) formHead(n *parse.Compound) {
    49  	head, err := eval.PurelyEvalCompound(n)
    50  	st := ui.Styles{}
    51  	if err == nil {
    52  		if e.GoodFormHead(head) {
    53  			st = styleForGoodCommand
    54  		} else {
    55  			st = styleForBadCommand
    56  		}
    57  	} else if err != eval.ErrImpure {
    58  		st = styleForBadCommand
    59  	}
    60  	if len(st) > 0 {
    61  		e.AddStyling(n.Begin(), n.End(), st.String())
    62  	}
    63  }
    64  
    65  func (e *Emitter) primary(n *parse.Primary) {
    66  	e.AddStyling(n.Begin(), n.End(), styleForPrimary[n.Type].String())
    67  }
    68  
    69  func (e *Emitter) sep(n *parse.Sep) {
    70  	septext := n.SourceText()
    71  	switch {
    72  	case strings.TrimSpace(septext) == "":
    73  		// Don't do anything. Whitespaces don't get any styling.
    74  	case strings.HasPrefix(septext, "#"):
    75  		// Comment.
    76  		e.AddStyling(n.Begin(), n.End(), styleForComment.String())
    77  	default:
    78  		e.AddStyling(n.Begin(), n.End(), styleForSep[septext])
    79  	}
    80  }