edit: Manage completion binding in its own struct.

This commit is contained in:
Qi Xiao 2018-02-07 00:04:14 -08:00
parent d30826d02d
commit ce76f493b2
4 changed files with 52 additions and 58 deletions

View File

@ -160,8 +160,6 @@ func makeNs(ed *Editor) eval.Ns {
} }
ns.AddBuiltinFns("edit:", fns) ns.AddBuiltinFns("edit:", fns)
ns.AddNs("completion",
initModeAPI("completion:", completionFns, &ed.completionBinding))
ns.AddNs("navigation", ns.AddNs("navigation",
initModeAPI("navigation:", navigationFns, &ed.navigationBinding)) initModeAPI("navigation:", navigationFns, &ed.navigationBinding))

View File

@ -15,21 +15,14 @@ import (
// Interface. // Interface.
var completionFns = map[string]func(*Editor){ var completionFns = map[string]func(*Editor){}
"smart-start": complSmartStart,
"start": complStart,
"up": complUp,
"up-cycle": complUpCycle,
"down": complDown,
"down-cycle": complDownCycle,
"left": complLeft,
"right": complRight,
"accept": complAccept,
"trigger-filter": complTriggerFilter,
"default": complDefault,
}
type completion struct { type completion struct {
binding BindingMap
completionState
}
type completionState struct {
complSpec complSpec
completer string completer string
@ -42,8 +35,37 @@ type completion struct {
height int height int
} }
func (*completion) Binding(ed *Editor, k ui.Key) eval.Callable { func init() { atEditorInit(initCompletion) }
return ed.completionBinding.GetOrDefault(k)
func initCompletion(ed *Editor, ns eval.Ns) {
c := &completion{binding: EmptyBindingMap}
ed.completion = c
subns := eval.Ns{
"binding": eval.NewVariableFromPtr(&c.binding),
}
subns.AddBuiltinFns("edit:completion:", map[string]interface{}{
"start": func() { startCompletionInner(ed, false) },
"smart-start": func() { startCompletionInner(ed, true) },
"up": func() { c.prev(false) },
"up-cycle": func() { c.prev(true) },
"down": func() { c.next(false) },
"down-cycle": func() { c.next(true) },
"left": c.left,
"right": c.right,
"accept": func() { complAccept(ed) },
"trigger-filter": c.triggerFilter,
"default": func() { complDefault(ed) },
})
ns.AddNs("completion", subns)
}
func (c *completion) Deinit() {
c.completionState = completionState{}
}
func (c *completion) Binding(ed *Editor, k ui.Key) eval.Callable {
return c.binding.GetOrDefault(k)
} }
func (c *completion) needScrollbar() bool { func (c *completion) needScrollbar() bool {
@ -63,42 +85,18 @@ func (c *completion) CursorOnModeLine() bool {
return c.filtering return c.filtering
} }
func complStart(ed *Editor) { func (c *completion) left() {
startCompletionInner(ed, false) if x := c.selected - c.height; x >= 0 {
} c.selected = x
func complSmartStart(ed *Editor) {
startCompletionInner(ed, true)
}
func complUp(ed *Editor) {
ed.completion.prev(false)
}
func complDown(ed *Editor) {
ed.completion.next(false)
}
func complLeft(ed *Editor) {
if c := ed.completion.selected - ed.completion.height; c >= 0 {
ed.completion.selected = c
} }
} }
func complRight(ed *Editor) { func (c *completion) right() {
if c := ed.completion.selected + ed.completion.height; c < len(ed.completion.filtered) { if x := c.selected + c.height; x < len(c.filtered) {
ed.completion.selected = c c.selected = x
} }
} }
func complUpCycle(ed *Editor) {
ed.completion.prev(true)
}
func complDownCycle(ed *Editor) {
ed.completion.next(true)
}
// acceptCompletion accepts currently selected completion candidate. // acceptCompletion accepts currently selected completion candidate.
func complAccept(ed *Editor) { func complAccept(ed *Editor) {
c := ed.completion c := ed.completion
@ -110,7 +108,7 @@ func complAccept(ed *Editor) {
func complDefault(ed *Editor) { func complDefault(ed *Editor) {
k := ed.lastKey k := ed.lastKey
c := &ed.completion c := ed.completion
if c.filtering && likeChar(k) { if c.filtering && likeChar(k) {
c.changeFilter(c.filter + string(k.Rune)) c.changeFilter(c.filter + string(k.Rune))
} else if c.filtering && k == (ui.Key{ui.Backspace, 0}) { } else if c.filtering && k == (ui.Key{ui.Backspace, 0}) {
@ -124,8 +122,7 @@ func complDefault(ed *Editor) {
} }
} }
func complTriggerFilter(ed *Editor) { func (c *completion) triggerFilter() {
c := &ed.completion
if c.filtering { if c.filtering {
c.filtering = false c.filtering = false
c.changeFilter("") c.changeFilter("")
@ -215,12 +212,12 @@ func startCompletionInner(ed *Editor, acceptPrefix bool) {
return return
} }
} }
ed.completion = completion{ ed.completion.completionState = completionState{
completer: completer, completer: completer,
complSpec: *complSpec, complSpec: *complSpec,
filtered: complSpec.candidates, filtered: complSpec.candidates,
} }
ed.mode = &ed.completion ed.SetMode(ed.completion)
} }
} }

View File

@ -40,7 +40,6 @@ type Editor struct {
active bool active bool
activeMutex sync.Mutex activeMutex sync.Mutex
completionBinding BindingMap
navigationBinding BindingMap navigationBinding BindingMap
listingBinding BindingMap listingBinding BindingMap
@ -66,9 +65,10 @@ type Editor struct {
maxHeight float64 maxHeight float64
// Modes. // Modes.
insert *insert insert *insert
command *command command *command
hist *hist hist *hist
completion *completion
editorState editorState
} }
@ -94,7 +94,6 @@ type editorState struct {
mode Mode mode Mode
completion completion
navigation navigation navigation navigation
// A cache of external commands, used in stylist. // A cache of external commands, used in stylist.

View File

@ -226,7 +226,7 @@ func (er *editorRenderer) Render(buf *ui.Buffer) {
// modify the text (and mark their part as modified). // modify the text (and mark their part as modified).
switch mode := es.mode.(type) { switch mode := es.mode.(type) {
case *completion: case *completion:
c := es.completion c := mode
clr.setComp(c.begin, c.end, c.selectedCandidate().code) clr.setComp(c.begin, c.end, c.selectedCandidate().code)
case *hist: case *hist:
begin := len(mode.walker.Prefix()) begin := len(mode.walker.Prefix())