Highlight compiling errors.

This fixes #64.
This commit is contained in:
Qi Xiao 2016-02-05 23:25:13 +00:00
parent 42d95df082
commit ddb7396046
7 changed files with 40 additions and 30 deletions

View File

@ -9,7 +9,6 @@ type colorist func(parse.Node, *Editor) string
var colorists = []colorist{
colorFormHead,
colorVariable,
}
func colorFormHead(n parse.Node, ed *Editor) string {
@ -43,17 +42,3 @@ func init() {
isBuiltinSpecial[name] = true
}
}
func colorVariable(n parse.Node, ed *Editor) string {
pn, ok := n.(*parse.Primary)
if !ok {
return ""
}
if pn.Type != parse.Variable || len(pn.Value) == 0 {
return ""
}
if ed.evaler.Global()[pn.Value[1:]] != nil {
return ""
}
return styleForBadVariable
}

View File

@ -8,8 +8,10 @@ import (
"strings"
"syscall"
"github.com/elves/elvish/errutil"
"github.com/elves/elvish/eval"
"github.com/elves/elvish/logutil"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/store"
"github.com/elves/elvish/sys"
)
@ -189,9 +191,28 @@ func (ed *Editor) pushTip(more string) {
func (ed *Editor) refresh() error {
// Re-lex the line, unless we are in modeCompletion
name := "[interacitve]"
src := ed.line
if ed.mode != modeCompletion {
// XXX Ignore error
ed.tokens, _ = tokenize(ed.line)
n, _ /*err*/ := parse.Parse(src)
if n == nil {
ed.tokens = []Token{{ParserError, src, nil, ""}}
} else {
ed.tokens = tokenize(src, n)
_, err := ed.evaler.Compile(name, src, n)
if err != nil {
if err, ok := err.(*errutil.ContextualError); ok {
ed.pushTip("compiler error highlighted")
p := err.Pos()
for i, token := range ed.tokens {
if token.Node.Begin() <= p && p < token.Node.End() {
ed.tokens[i].MoreStyle += styleForCompilerError
break
}
}
}
}
}
for i, t := range ed.tokens {
for _, colorist := range colorists {
ed.tokens[i].MoreStyle += colorist(t.Node, ed)

View File

@ -43,7 +43,8 @@ var styleForSep = map[string]string{
// Styles for semantic coloring.
var (
styleForGoodCommand = ";32"
styleForBadCommand = ";31"
styleForBadVariable = ";31;3"
styleForGoodCommand = ";32"
styleForBadCommand = ";31"
styleForBadVariable = ";31;3"
styleForCompilerError = ";31;3"
)

View File

@ -26,12 +26,8 @@ func parserError(text string) Token {
return Token{ParserError, text, nil, ""}
}
func tokenize(src string) ([]Token, error) {
func tokenize(src string, n parse.Node) []Token {
lastEnd := 0
n, err := parse.Parse(src)
if n == nil {
return []Token{{ParserError, src, nil, ""}}, err
}
tokenCh := make(chan Token, tokensBufferSize)
tokens := []Token{}
@ -55,7 +51,7 @@ func tokenize(src string) ([]Token, error) {
if lastEnd != len(src) {
tokens = append(tokens, parserError(src[lastEnd:]))
}
return tokens, err
return tokens
}
func produceTokens(n parse.Node, tokenCh chan<- Token) {

View File

@ -15,6 +15,7 @@ import (
type ContextualError struct {
srcname string
title string
pos int
line string
lineno int
colno int
@ -24,7 +25,11 @@ type ContextualError struct {
// NewContextualError creates a new ContextualError.
func NewContextualError(srcname, title, text string, pos int, format string, args ...interface{}) *ContextualError {
lineno, colno, line := strutil.FindContext(text, pos)
return &ContextualError{srcname, title, line, lineno, colno, fmt.Sprintf(format, args...)}
return &ContextualError{srcname, title, pos, line, lineno, colno, fmt.Sprintf(format, args...)}
}
func (e *ContextualError) Pos() int {
return e.pos
}
// Error implements the error interface. It returns a compact representation of

View File

@ -165,7 +165,7 @@ func (ev *Evaler) Eval(name, text string, n *parse.Chunk) error {
}
func (ev *Evaler) evalWithOut(name, text string, n *parse.Chunk, out *port) error {
op, err := compile(name, text, makeScope(ev.global), n)
op, err := ev.Compile(name, text, n)
if err != nil {
out.close()
return err
@ -183,6 +183,10 @@ func (ev *Evaler) evalWithOut(name, text string, n *parse.Chunk, out *port) erro
return ex
}
func (ev *Evaler) Compile(name, text string, n *parse.Chunk) (op, error) {
return compile(name, text, makeScope(ev.global), n)
}
// peval evaluates an op in a protected environment so that calls to errorf are
// wrapped in an Error.
func (ec *evalCtx) peval(op op) (ex error) {

View File

@ -150,7 +150,6 @@ func (fn *Form) parse(ps *parser, cut runePred) {
if len(fn.Assignments) == 0 {
ps.error(shouldBeCompound)
}
return
}
fn.setHead(parseCompound(ps, cut))
parseSpaces(fn, ps)
@ -698,7 +697,6 @@ func (pn *Primary) lambda(ps *parser) {
pn.Type = Lambda
if !startsChunk(ps.peek(), nil) && ps.peek() != '}' {
ps.error(shouldBeChunk)
return
}
pn.setChunk(parseChunk(ps, nil))
if !parseSep(pn, ps, '}') {