mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-15 20:17:50 +08:00
81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
package edit
|
|
|
|
import (
|
|
"github.com/xiaq/elvish/eval"
|
|
"github.com/xiaq/elvish/parse"
|
|
)
|
|
|
|
// Pseudo-ItemType's used by the Highlighter. They are given negative values
|
|
// to avoid conflict with genuine ItemType's. They can be regarded as some
|
|
// "sub-ItemType" of ItemBare, since only barewords are inspected and marked
|
|
// with these pseudo-ItemType's.
|
|
const (
|
|
ItemValidCommand parse.ItemType = -iota - 1
|
|
ItemInvalidCommand
|
|
ItemValidVariable
|
|
ItemInvalidVariable
|
|
)
|
|
|
|
// Highlighter is an enhanced Lexer with the knowledge of the validity of
|
|
// command names and variable names.
|
|
//
|
|
// Generally speaking, this is not possible without properly parsing and
|
|
// evaluating the source, performing its side effects. However in the case of
|
|
// single bareword terms, some heuristics can be applied. Be noted though, the
|
|
// heuristics can be quite fragile in case of syntax changes, so it's
|
|
// important to keep the syntax either simple (so that the heuristics is easy
|
|
// to implement) or stable (so that the heuristics doesn't have to be
|
|
// modified), or both.
|
|
type Highlighter struct {
|
|
lexer *parse.Lexer
|
|
ev *eval.Evaluator
|
|
items chan parse.Item
|
|
}
|
|
|
|
func (hl *Highlighter) run() {
|
|
command := true
|
|
variable := false
|
|
|
|
for token := range hl.lexer.Chan() {
|
|
switch token.Typ {
|
|
case parse.ItemBare:
|
|
// Mangle token.Typ
|
|
if command {
|
|
// Check validity of command
|
|
if _, _, err := hl.ev.ResolveCommand(token.Val); err == nil {
|
|
token.Typ = ItemValidCommand
|
|
} else {
|
|
token.Typ = ItemInvalidCommand
|
|
}
|
|
} else if variable {
|
|
if _, err := hl.ev.ResolveVar(token.Val); err == nil {
|
|
token.Typ = ItemValidVariable
|
|
} else {
|
|
token.Typ = ItemInvalidVariable
|
|
}
|
|
}
|
|
command = false
|
|
variable = false
|
|
case parse.ItemSemicolon, parse.ItemPipe, parse.ItemEndOfLine:
|
|
// NOTE ItemPipe can also be the pipe in {|a b| command...}
|
|
command = true
|
|
case parse.ItemDollar:
|
|
variable = true
|
|
case parse.ItemSpace:
|
|
variable = false
|
|
default:
|
|
command = false
|
|
variable = false
|
|
}
|
|
// TODO highlight `echo` in `{ echo a }`
|
|
hl.items <- token
|
|
}
|
|
close(hl.items)
|
|
}
|
|
|
|
func Highlight(name, input string, ev *eval.Evaluator) chan parse.Item {
|
|
hl := &Highlighter{parse.Lex(name, input), ev, make(chan parse.Item)}
|
|
go hl.run()
|
|
return hl.items
|
|
}
|