mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-13 09:57:51 +08:00
newedit/highlighter: Highlighter now relays late updates.
This commit is contained in:
parent
25bdb6ecd7
commit
28cbb3112e
|
@ -57,7 +57,8 @@ func (ed *Editor) State() *types.State {
|
|||
}
|
||||
|
||||
// A special event type signalling something has seen a late update and a
|
||||
// refresh is needed. This is currently only used for refreshing prompts.
|
||||
// refresh is needed. This is currently used for refreshing prompts and
|
||||
// highlighting.
|
||||
type lateUpdate struct{}
|
||||
|
||||
func (ed *Editor) handle(e event) handleResult {
|
||||
|
@ -197,9 +198,10 @@ func (ed *Editor) ReadCode() (string, error) {
|
|||
}()
|
||||
}
|
||||
|
||||
// Relay late prompt/rprompt updates.
|
||||
stopRelayLateUpdates := make(chan struct{})
|
||||
defer close(stopRelayLateUpdates)
|
||||
|
||||
// Relay late prompt/rprompt updates.
|
||||
relayLateUpdates := func(p Prompt) {
|
||||
if p == nil {
|
||||
return
|
||||
|
@ -220,7 +222,21 @@ func (ed *Editor) ReadCode() (string, error) {
|
|||
relayLateUpdates(ed.Prompt)
|
||||
relayLateUpdates(ed.RPrompt)
|
||||
|
||||
// TODO: Relay highlighter late updates.
|
||||
// Relay highlighter late updates.
|
||||
if ed.Highlighter != nil {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-ed.Highlighter.LateUpdates():
|
||||
ed.loop.Input(lateUpdate{})
|
||||
case <-stopRelayLateUpdates:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Trigger an initial prompt update.
|
||||
ed.triggerPrompts(true)
|
||||
|
|
|
@ -14,7 +14,7 @@ type Dep struct {
|
|||
}
|
||||
|
||||
// Highlights a piece of Elvish code.
|
||||
func highlight(code string, dep Dep) (styled.Text, []error) {
|
||||
func highlight(code string, dep Dep, lateCb func(styled.Text)) (styled.Text, []error) {
|
||||
var errors []error
|
||||
|
||||
n, errParse := parse.AsChunk("[interactive]", code)
|
||||
|
|
|
@ -43,22 +43,24 @@ func (anyMatcher) Match(tt.RetValue) bool { return true }
|
|||
func TestHighlight(t *testing.T) {
|
||||
any := anyMatcher{}
|
||||
|
||||
dep := Dep{}
|
||||
hl := func(code string) (styled.Text, []error) {
|
||||
return highlight(code, Dep{}, nopLateCb)
|
||||
}
|
||||
|
||||
tt.Test(t, tt.Fn("highlight", highlight), tt.Table{
|
||||
Args("ls", dep).Rets(styled.Text{
|
||||
tt.Test(t, tt.Fn("highlight", hl), tt.Table{
|
||||
Args("ls").Rets(styled.Text{
|
||||
&styled.Segment{styled.Style{Foreground: "green"}, "ls"},
|
||||
}, noErrors),
|
||||
Args(" ls\n", dep).Rets(styled.Text{
|
||||
Args(" ls\n").Rets(styled.Text{
|
||||
styled.UnstyledSegment(" "),
|
||||
&styled.Segment{styled.Style{Foreground: "green"}, "ls"},
|
||||
styled.UnstyledSegment("\n"),
|
||||
}, noErrors),
|
||||
// Parse error
|
||||
Args("ls ]", dep).Rets(any, matchErrors(parseErrorMatcher{3, 4})),
|
||||
Args("ls ]").Rets(any, matchErrors(parseErrorMatcher{3, 4})),
|
||||
// Errors at the end are elided
|
||||
Args("ls $", dep).Rets(any, noErrors),
|
||||
Args("ls [", dep).Rets(any, noErrors),
|
||||
Args("ls $").Rets(any, noErrors),
|
||||
Args("ls [").Rets(any, noErrors),
|
||||
|
||||
// TODO: Test for multiple parse errors
|
||||
})
|
||||
|
@ -85,31 +87,33 @@ func TestHighlight_Check(t *testing.T) {
|
|||
}
|
||||
|
||||
checkError = fakeCheckError{0, 2}
|
||||
_, errors := highlight("code", dep)
|
||||
_, errors := highlight("code", dep, nopLateCb)
|
||||
if !reflect.DeepEqual(errors, []error{checkError}) {
|
||||
t.Errorf("Got errors %v, want %v", errors, []error{checkError})
|
||||
}
|
||||
|
||||
// Errors at the end
|
||||
checkError = fakeCheckError{4, 4}
|
||||
_, errors = highlight("code", dep)
|
||||
_, errors = highlight("code", dep, nopLateCb)
|
||||
if len(errors) != 0 {
|
||||
t.Errorf("Got errors %v, want 0 error", errors)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHighlight_HasCommand(t *testing.T) {
|
||||
dep := Dep{
|
||||
HasCommand: func(cmd string) bool {
|
||||
return cmd == "ls"
|
||||
},
|
||||
hasCommand := func(cmd string) bool { return cmd == "ls" }
|
||||
hl := func(code string) (styled.Text, []error) {
|
||||
return highlight(code, Dep{HasCommand: hasCommand}, nopLateCb)
|
||||
}
|
||||
tt.Test(t, tt.Fn("highlight", highlight), tt.Table{
|
||||
Args("ls", dep).Rets(styled.Text{
|
||||
|
||||
tt.Test(t, tt.Fn("highlight", hl), tt.Table{
|
||||
Args("ls").Rets(styled.Text{
|
||||
&styled.Segment{styled.Style{Foreground: "green"}, "ls"},
|
||||
}, noErrors),
|
||||
Args("echo", dep).Rets(styled.Text{
|
||||
Args("echo").Rets(styled.Text{
|
||||
&styled.Segment{styled.Style{Foreground: "red"}, "echo"},
|
||||
}, noErrors),
|
||||
})
|
||||
}
|
||||
|
||||
func nopLateCb(styled.Text) {}
|
||||
|
|
|
@ -1,24 +1,50 @@
|
|||
package highlight
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/elves/elvish/styled"
|
||||
)
|
||||
|
||||
const latesBufferSize = 128
|
||||
|
||||
// Highlighter is a code highlighter that can deliver results asynchronously.
|
||||
type Highlighter struct {
|
||||
dep Dep
|
||||
dep Dep
|
||||
state state
|
||||
lates chan struct{}
|
||||
}
|
||||
|
||||
type state struct {
|
||||
sync.RWMutex
|
||||
code string
|
||||
styledCode styled.Text
|
||||
errors []error
|
||||
}
|
||||
|
||||
func NewHighlighter(dep Dep) *Highlighter {
|
||||
return &Highlighter{dep}
|
||||
return &Highlighter{dep, state{}, make(chan struct{}, latesBufferSize)}
|
||||
}
|
||||
|
||||
// Get returns the highlighted code and static errors found in the code.
|
||||
func (hl *Highlighter) Get(code string) (styled.Text, []error) {
|
||||
return highlight(code, hl.dep)
|
||||
hl.state.RLock()
|
||||
if code == hl.state.code {
|
||||
hl.state.RUnlock()
|
||||
return hl.state.styledCode, hl.state.errors
|
||||
}
|
||||
hl.state.RUnlock()
|
||||
|
||||
lateCb := func(styledCode styled.Text) {
|
||||
hl.state.Lock()
|
||||
hl.state.styledCode = styledCode
|
||||
hl.state.Unlock()
|
||||
hl.lates <- struct{}{}
|
||||
}
|
||||
return highlight(code, hl.dep, lateCb)
|
||||
}
|
||||
|
||||
// LateUpdates returns a channel for notifying late updates.
|
||||
func (hl *Highlighter) LateUpdates() <-chan struct{} {
|
||||
return nil
|
||||
return hl.lates
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user