Finish autocomplete

This commit is contained in:
Zachary Yedidia
2019-01-24 18:09:57 -05:00
parent ad487807a5
commit 0e4faf108d
6 changed files with 91 additions and 60 deletions

View File

@@ -14,7 +14,7 @@ import (
// for example with `vsplit filename`.
// CommandComplete autocompletes commands
func CommandComplete(b *buffer.Buffer) (string, []string) {
func CommandComplete(b *buffer.Buffer) ([]string, []string) {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@@ -25,15 +25,16 @@ func CommandComplete(b *buffer.Buffer) (string, []string) {
}
}
var chosen string
if len(suggestions) == 1 {
chosen = util.SliceEndStr(suggestions[0], c.X-argstart)
completions := make([]string, len(suggestions))
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return chosen, suggestions
return completions, suggestions
}
// HelpComplete autocompletes help topics
func HelpComplete(b *buffer.Buffer) (string, []string) {
func HelpComplete(b *buffer.Buffer) ([]string, []string) {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@@ -46,16 +47,16 @@ func HelpComplete(b *buffer.Buffer) (string, []string) {
}
}
var chosen string
if len(suggestions) == 1 {
chosen = util.SliceEndStr(suggestions[0], c.X-argstart)
completions := make([]string, len(suggestions))
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return chosen, suggestions
return completions, suggestions
}
// ColorschemeComplete tab-completes names of colorschemes.
// colorschemeComplete tab-completes names of colorschemes.
// This is just a heper value for OptionValueComplete
func ColorschemeComplete(input string) (string, []string) {
func colorschemeComplete(input string) (string, []string) {
var suggestions []string
files := config.ListRuntimeFiles(config.RTColorscheme)
@@ -83,7 +84,7 @@ func contains(s []string, e string) bool {
}
// OptionComplete autocompletes options
func OptionComplete(b *buffer.Buffer) (string, []string) {
func OptionComplete(b *buffer.Buffer) ([]string, []string) {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@@ -100,15 +101,15 @@ func OptionComplete(b *buffer.Buffer) (string, []string) {
}
}
var chosen string
if len(suggestions) == 1 {
chosen = util.SliceEndStr(suggestions[0], c.X-argstart)
completions := make([]string, len(suggestions))
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return chosen, suggestions
return completions, suggestions
}
// OptionValueComplete completes values for various options
func OptionValueComplete(b *buffer.Buffer) (string, []string) {
func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
c := b.GetActiveCursor()
l := b.LineBytes(c.Y)
l = util.SliceStart(l, c.X)
@@ -167,7 +168,7 @@ func OptionValueComplete(b *buffer.Buffer) (string, []string) {
case string:
switch inputOpt {
case "colorscheme":
_, suggestions = ColorschemeComplete(input)
_, suggestions = colorschemeComplete(input)
case "fileformat":
if strings.HasPrefix("unix", input) {
suggestions = append(suggestions, "unix")
@@ -185,11 +186,11 @@ func OptionValueComplete(b *buffer.Buffer) (string, []string) {
}
}
var chosen string
if len(suggestions) == 1 {
chosen = util.SliceEndStr(suggestions[0], c.X-argstart)
completions := make([]string, len(suggestions))
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return chosen, suggestions
return completions, suggestions
}
// // MakeCompletion registers a function from a plugin for autocomplete commands

View File

@@ -163,8 +163,12 @@ func (h *InfoPane) CursorDown() {
h.DownHistory(h.History[h.PromptType])
}
func (h *InfoPane) InsertTab() {
// TODO: autocomplete
b := h.Buf
if b.HasSuggestions {
b.CycleAutocomplete()
return
}
c := b.GetActiveCursor()
l := b.LineBytes(0)
l = util.SliceStart(l, c.X)
@@ -172,23 +176,15 @@ func (h *InfoPane) InsertTab() {
args := bytes.Split(l, []byte{' '})
cmd := string(args[0])
var ins string
var suggestions []string
if len(args) == 1 {
ins, suggestions = CommandComplete(b)
b.Autocomplete(CommandComplete)
} else {
if action, ok := commands[cmd]; ok {
if action.completer != nil {
ins, suggestions = action.completer(b)
b.Autocomplete(action.completer)
}
}
}
if len(suggestions) == 1 {
b.Insert(c.Loc, ins)
} else if len(suggestions) > 1 {
h.MakeSuggestions(suggestions)
}
}
func (h *InfoPane) InsertNewline() {
if !h.HasYN {

View File

@@ -10,14 +10,47 @@ import (
"github.com/zyedidia/micro/cmd/micro/util"
)
type Completer func(*Buffer) (string, []string)
// A Completer is a function that takes a buffer and returns info
// describing what autocompletions should be inserted at the current
// cursor location
// It returns a list of string suggestions which will be inserted at
// the current cursor location if selected as well as a list of
// suggestion names which can be displayed in a autocomplete box or
// other UI element
type Completer func(*Buffer) ([]string, []string)
func (b *Buffer) GetSuggestions() {
}
func (b *Buffer) Autocomplete(c Completer) {
b.Completions, b.Suggestions = c(b)
if len(b.Completions) != len(b.Suggestions) || len(b.Completions) == 0 {
return
}
b.CurSuggestion = -1
b.CycleAutocomplete()
}
func (b *Buffer) CycleAutocomplete() {
prevSuggestion := b.CurSuggestion
b.CurSuggestion++
if b.CurSuggestion >= len(b.Suggestions) || b.CurSuggestion < 0 {
b.CurSuggestion = 0
}
c := b.GetActiveCursor()
start := c.Loc
end := c.Loc
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
start = end.Move(-utf8.RuneCountInString(b.Completions[prevSuggestion]), b)
} else {
end = start.Move(1, b)
}
b.Replace(start, end, b.Completions[b.CurSuggestion])
b.HasSuggestions = true
}
func GetArg(b *Buffer) (string, int) {
@@ -39,7 +72,7 @@ func GetArg(b *Buffer) (string, int) {
}
// FileComplete autocompletes filenames
func FileComplete(b *Buffer) (string, []string) {
func FileComplete(b *Buffer) ([]string, []string) {
c := b.GetActiveCursor()
input, argstart := GetArg(b)
@@ -57,10 +90,11 @@ func FileComplete(b *Buffer) (string, []string) {
files, err = ioutil.ReadDir(".")
}
var suggestions []string
if err != nil {
return "", suggestions
return nil, nil
}
var suggestions []string
for _, f := range files {
name := f.Name()
if f.IsDir() {
@@ -71,19 +105,16 @@ func FileComplete(b *Buffer) (string, []string) {
}
}
var chosen string
if len(suggestions) == 1 {
completions := make([]string, len(suggestions))
for i := range suggestions {
var complete string
if len(dirs) > 1 {
chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep + suggestions[0]
complete = strings.Join(dirs[:len(dirs)-1], sep) + sep + suggestions[i]
} else {
chosen = suggestions[0]
}
} else {
if len(dirs) > 1 {
chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep
complete = suggestions[i]
}
completions[i] = util.SliceEndStr(complete, c.X-argstart)
}
chosen = util.SliceEndStr(chosen, c.X-argstart)
return chosen, suggestions
return completions, suggestions
}

View File

@@ -52,14 +52,19 @@ type SharedBuffer struct {
Type BufType
isModified bool
// Whether or not suggestions can be autocompleted must be shared because
// it changes based on how the buffer has changed
HasSuggestions bool
}
func (b *SharedBuffer) insert(pos Loc, value []byte) {
b.isModified = true
b.HasSuggestions = false
b.LineArray.insert(pos, value)
}
func (b *SharedBuffer) remove(start, end Loc) []byte {
b.isModified = true
b.HasSuggestions = false
return b.LineArray.remove(start, end)
}
@@ -94,7 +99,9 @@ type Buffer struct {
// Settings customized by the user
Settings map[string]interface{}
Suggestions []string
Suggestions []string
Completions []string
CurSuggestion int
Messages []*Message
}

View File

@@ -190,8 +190,7 @@ func (i *InfoWindow) Display() {
}
}
if i.HasSuggestions {
i.HasSuggestions = false
if i.HasSuggestions && len(i.Suggestions) > 1 {
statusLineStyle := config.DefStyle.Reverse(true)
if style, ok := config.Colorscheme["statusline"]; ok {
statusLineStyle = style
@@ -201,9 +200,13 @@ func (i *InfoWindow) Display() {
keymenuOffset = len(keydisplay)
}
x := 0
for _, s := range i.Suggestions {
for j, s := range i.Suggestions {
style := statusLineStyle
if i.CurSuggestion == j {
style = style.Reverse(true)
}
for _, r := range s {
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, statusLineStyle)
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style)
x++
if x >= i.Width {
return

View File

@@ -16,8 +16,6 @@ type InfoBuf struct {
HasError bool
HasYN bool
HasSuggestions bool
PromptType string
Msg string
@@ -161,8 +159,3 @@ func (i *InfoBuf) Reset() {
i.HasPrompt, i.HasMessage, i.HasError = false, false, false
i.HasGutter = false
}
func (i *InfoBuf) MakeSuggestions(s []string) {
i.HasSuggestions = true
i.Suggestions = s
}