mirror of
https://github.com/zyedidia/micro.git
synced 2026-02-09 00:20:19 +09:00
Finish autocomplete
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user