github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/edit/highlight/emitter.go (about) 1 package highlight 2 3 import ( 4 "strings" 5 6 "github.com/u-root/u-root/cmds/elvish/edit/ui" 7 "github.com/u-root/u-root/cmds/elvish/eval" 8 "github.com/u-root/u-root/cmds/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 // Special forms 46 switch n.Head.SourceText() { 47 case "if": 48 for i := 2; i < len(n.Args); i += 2 { 49 a := n.Args[i] 50 argText := a.SourceText() 51 if argText == "elif" || argText == "else" { 52 e.AddStyling(a.Begin(), a.End(), styleForSep[argText]) 53 } 54 } 55 case "for": 56 if len(n.Args) >= 1 && len(n.Args[0].Indexings) > 0 { 57 v := n.Args[0].Indexings[0].Head 58 e.AddStyling(v.Begin(), v.End(), styleForGoodVariable.String()) 59 } 60 if len(n.Args) >= 4 && n.Args[3].SourceText() == "else" { 61 a := n.Args[3] 62 e.AddStyling(a.Begin(), a.End(), styleForSep["else"]) 63 } 64 case "try": 65 i := 1 66 highlightKeyword := func(name string) bool { 67 if i >= len(n.Args) { 68 return false 69 } 70 a := n.Args[i] 71 if a.SourceText() != name { 72 return false 73 } 74 e.AddStyling(a.Begin(), a.End(), styleForSep[name]) 75 return true 76 } 77 if highlightKeyword("except") { 78 if i+1 < len(n.Args) && len(n.Args[i+1].Indexings) > 0 { 79 v := n.Args[i+1].Indexings[0] 80 e.AddStyling(v.Begin(), v.End(), styleForGoodVariable.String()) 81 } 82 i += 3 83 } 84 if highlightKeyword("else") { 85 i += 2 86 } 87 highlightKeyword("finally") 88 } 89 // TODO(xiaq): Handle other special forms. 90 } 91 } 92 93 func (e *Emitter) formHead(n *parse.Compound) { 94 head, err := eval.PurelyEvalCompound(n) 95 st := ui.Styles{} 96 if err == nil { 97 if e.GoodFormHead(head) { 98 st = styleForGoodCommand 99 } else { 100 st = styleForBadCommand 101 } 102 } else if err != eval.ErrImpure { 103 st = styleForBadCommand 104 } 105 if len(st) > 0 { 106 e.AddStyling(n.Begin(), n.End(), st.String()) 107 } 108 } 109 110 func (e *Emitter) primary(n *parse.Primary) { 111 e.AddStyling(n.Begin(), n.End(), styleForPrimary[n.Type].String()) 112 } 113 114 func (e *Emitter) sep(n *parse.Sep) { 115 septext := n.SourceText() 116 switch { 117 case strings.TrimSpace(septext) == "": 118 // Don't do anything. Whitespaces don't get any styling. 119 case strings.HasPrefix(septext, "#"): 120 // Comment. 121 e.AddStyling(n.Begin(), n.End(), styleForComment.String()) 122 default: 123 e.AddStyling(n.Begin(), n.End(), styleForSep[septext]) 124 } 125 }