package highlight
import (
)
var sourceText = parse.SourceText
type region struct {
begin int
end int
kind regionKind
typ string
}
type regionKind int
const (
lexicalRegion regionKind = iota
semanticRegion
)
const (
barewordRegion = "bareword"
singleQuotedRegion = "single-quoted"
doubleQuotedRegion = "double-quoted"
variableRegion = "variable"
wildcardRegion = "wildcard"
tildeRegion = "tilde"
commentRegion = "comment"
)
const (
commandRegion = "command"
keywordRegion = "keyword"
errorRegion = "error"
)
func ( parse.Node) []region {
:= getRegionsInner()
= fixRegions()
return
}
func ( parse.Node) []region {
var []region
emitRegions(, func( parse.Node, regionKind, string) {
= append(, region{.Range().From, .Range().To, , })
})
return
}
func ( []region) []region {
sort.Slice(, func(, int) bool {
if [].begin < [].begin {
return true
}
if [].begin == [].begin {
return [].kind == semanticRegion && [].kind == lexicalRegion
}
return false
})
var []region
:= 0
for , := range {
if .begin < {
continue
}
= append(, )
= .end
}
return
}
func ( parse.Node, func(parse.Node, regionKind, string)) {
switch n := .(type) {
case *parse.Form:
emitRegionsInForm(, )
case *parse.Primary:
emitRegionsInPrimary(, )
case *parse.Sep:
emitRegionsInSep(, )
}
for , := range parse.Children() {
(, )
}
}
func ( *parse.Form, func(parse.Node, regionKind, string)) {
for , := range .Assignments {
if .Left != nil && .Left.Head != nil {
(.Left.Head, semanticRegion, variableRegion)
}
}
if .Head == nil {
return
}
:= sourceText(.Head)
switch {
case "var", "set":
emitRegionsInVarSet(, )
case "if":
emitRegionsInIf(, )
case "for":
emitRegionsInFor(, )
case "try":
emitRegionsInTry(, )
}
if !eval.IsBuiltinSpecial[] {
for , := range .Args {
if parse.SourceText() == "=" {
emitVariableRegion(.Head, )
for := 0; < ; ++ {
emitVariableRegion(.Args[], )
}
return
}
}
}
if isBarewordCompound(.Head) {
(.Head, semanticRegion, commandRegion)
}
}
func ( *parse.Form, func(parse.Node, regionKind, string)) {
for , := range .Args {
if parse.SourceText() == "=" {
(, semanticRegion, keywordRegion)
break
}
emitVariableRegion(, )
}
}
func ( *parse.Compound, func(parse.Node, regionKind, string)) {
if != nil && len(.Indexings) == 1 && .Indexings[0].Head != nil {
(.Indexings[0].Head, semanticRegion, variableRegion)
}
}
func ( *parse.Compound) bool {
return len(.Indexings) == 1 && len(.Indexings[0].Indicies) == 0 && .Indexings[0].Head.Type == parse.Bareword
}
func ( *parse.Form, func(parse.Node, regionKind, string)) {
for := 2; < len(.Args); += 2 {
:= .Args[]
if := sourceText(); == "elif" || == "else" {
(, semanticRegion, keywordRegion)
}
}
}
func ( *parse.Form, func(parse.Node, regionKind, string)) {
if 0 < len(.Args) && len(.Args[0].Indexings) > 0 {
(.Args[0].Indexings[0].Head, semanticRegion, variableRegion)
}
if 3 < len(.Args) && sourceText(.Args[3]) == "else" {
(.Args[3], semanticRegion, keywordRegion)
}
}
func ( *parse.Form, func(parse.Node, regionKind, string)) {
:= 1
:= func( string) bool {
if < len(.Args) && sourceText(.Args[]) == {
(.Args[], semanticRegion, keywordRegion)
return true
}
return false
}
if ("except") {
if +1 < len(.Args) && len(.Args[+1].Indexings) > 0 {
(.Args[+1], semanticRegion, variableRegion)
}
+= 3
}
if ("else") {
+= 2
}
("finally")
}
func ( *parse.Primary, func(parse.Node, regionKind, string)) {
switch .Type {
case parse.Bareword:
(, lexicalRegion, barewordRegion)
case parse.SingleQuoted:
(, lexicalRegion, singleQuotedRegion)
case parse.DoubleQuoted:
(, lexicalRegion, doubleQuotedRegion)
case parse.Variable:
(, lexicalRegion, variableRegion)
case parse.Wildcard:
(, lexicalRegion, wildcardRegion)
case parse.Tilde:
(, lexicalRegion, tildeRegion)
}
}
func ( *parse.Sep, func(parse.Node, regionKind, string)) {
:= sourceText()
:= strings.TrimLeftFunc(, parse.IsWhitespace)
switch {
case == "":
case strings.HasPrefix(, "#"):
(, lexicalRegion, commentRegion)
default:
(, lexicalRegion, )
}
}