mirror of
https://github.com/zyedidia/micro.git
synced 2024-09-19 07:57:49 +03:00
342 lines
8.6 KiB
Go
342 lines
8.6 KiB
Go
package action
|
|
|
|
import (
|
|
"bytes"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/zyedidia/micro/v2/internal/buffer"
|
|
"github.com/zyedidia/micro/v2/internal/config"
|
|
"github.com/zyedidia/micro/v2/internal/util"
|
|
"github.com/zyedidia/micro/v2/pkg/highlight"
|
|
)
|
|
|
|
// This file is meant (for now) for autocompletion in command mode, not
|
|
// while coding. This helps micro autocomplete commands and then filenames
|
|
// for example with `vsplit filename`.
|
|
|
|
// CommandComplete autocompletes commands
|
|
func CommandComplete(b *buffer.Buffer) ([]string, []string) {
|
|
c := b.GetActiveCursor()
|
|
input, argstart := b.GetArg()
|
|
|
|
var suggestions []string
|
|
for cmd := range commands {
|
|
if strings.HasPrefix(cmd, input) {
|
|
suggestions = append(suggestions, cmd)
|
|
}
|
|
}
|
|
|
|
sort.Strings(suggestions)
|
|
completions := make([]string, len(suggestions))
|
|
for i := range suggestions {
|
|
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
}
|
|
|
|
return completions, suggestions
|
|
}
|
|
|
|
// HelpComplete autocompletes help topics
|
|
func HelpComplete(b *buffer.Buffer) ([]string, []string) {
|
|
c := b.GetActiveCursor()
|
|
input, argstart := b.GetArg()
|
|
|
|
var suggestions []string
|
|
|
|
for _, file := range config.ListRuntimeFiles(config.RTHelp) {
|
|
topic := file.Name()
|
|
if strings.HasPrefix(topic, input) {
|
|
suggestions = append(suggestions, topic)
|
|
}
|
|
}
|
|
|
|
sort.Strings(suggestions)
|
|
completions := make([]string, len(suggestions))
|
|
for i := range suggestions {
|
|
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
}
|
|
return completions, suggestions
|
|
}
|
|
|
|
// colorschemeComplete tab-completes names of colorschemes.
|
|
// This is just a heper value for OptionValueComplete
|
|
func colorschemeComplete(input string) (string, []string) {
|
|
var suggestions []string
|
|
files := config.ListRuntimeFiles(config.RTColorscheme)
|
|
|
|
for _, f := range files {
|
|
if strings.HasPrefix(f.Name(), input) {
|
|
suggestions = append(suggestions, f.Name())
|
|
}
|
|
}
|
|
|
|
var chosen string
|
|
if len(suggestions) == 1 {
|
|
chosen = suggestions[0]
|
|
}
|
|
|
|
return chosen, suggestions
|
|
}
|
|
|
|
// filetypeComplete autocompletes filetype
|
|
func filetypeComplete(input string) (string, []string) {
|
|
var suggestions []string
|
|
|
|
// We cannot match filetypes just by names of syntax files,
|
|
// since those names may be different from the actual filetype values
|
|
// specified inside syntax files (e.g. "c++" filetype in cpp.yaml).
|
|
// So we need to parse filetype values out of those files.
|
|
for _, f := range config.ListRealRuntimeFiles(config.RTSyntax) {
|
|
data, err := f.Data()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
header, err := highlight.MakeHeaderYaml(data)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
// Prevent duplicated defaults
|
|
if header.FileType == "off" || header.FileType == "unknown" {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(header.FileType, input) {
|
|
suggestions = append(suggestions, header.FileType)
|
|
}
|
|
}
|
|
headerLoop:
|
|
for _, f := range config.ListRuntimeFiles(config.RTSyntaxHeader) {
|
|
data, err := f.Data()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
header, err := highlight.MakeHeader(data)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, v := range suggestions {
|
|
if v == header.FileType {
|
|
continue headerLoop
|
|
}
|
|
}
|
|
if strings.HasPrefix(header.FileType, input) {
|
|
suggestions = append(suggestions, header.FileType)
|
|
}
|
|
}
|
|
|
|
if strings.HasPrefix("off", input) {
|
|
suggestions = append(suggestions, "off")
|
|
}
|
|
|
|
var chosen string
|
|
if len(suggestions) == 1 {
|
|
chosen = suggestions[0]
|
|
}
|
|
|
|
return chosen, suggestions
|
|
}
|
|
|
|
func contains(s []string, e string) bool {
|
|
for _, a := range s {
|
|
if a == e {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// OptionComplete autocompletes options
|
|
func OptionComplete(b *buffer.Buffer) ([]string, []string) {
|
|
c := b.GetActiveCursor()
|
|
input, argstart := b.GetArg()
|
|
|
|
var suggestions []string
|
|
for option := range config.GlobalSettings {
|
|
if strings.HasPrefix(option, input) {
|
|
suggestions = append(suggestions, option)
|
|
}
|
|
}
|
|
// for option := range localSettings {
|
|
// if strings.HasPrefix(option, input) && !contains(suggestions, option) {
|
|
// suggestions = append(suggestions, option)
|
|
// }
|
|
// }
|
|
|
|
sort.Strings(suggestions)
|
|
completions := make([]string, len(suggestions))
|
|
for i := range suggestions {
|
|
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
}
|
|
return completions, suggestions
|
|
}
|
|
|
|
// OptionValueComplete completes values for various options
|
|
func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
|
|
c := b.GetActiveCursor()
|
|
l := b.LineBytes(c.Y)
|
|
l = util.SliceStart(l, c.X)
|
|
input, argstart := b.GetArg()
|
|
|
|
completeValue := false
|
|
args := bytes.Split(l, []byte{' '})
|
|
if len(args) >= 2 {
|
|
// localSettings := config.DefaultLocalSettings()
|
|
for option := range config.GlobalSettings {
|
|
if option == string(args[len(args)-2]) {
|
|
completeValue = true
|
|
break
|
|
}
|
|
}
|
|
// for option := range localSettings {
|
|
// if option == string(args[len(args)-2]) {
|
|
// completeValue = true
|
|
// break
|
|
// }
|
|
// }
|
|
}
|
|
if !completeValue {
|
|
return OptionComplete(b)
|
|
}
|
|
|
|
inputOpt := string(args[len(args)-2])
|
|
|
|
inputOpt = strings.TrimSpace(inputOpt)
|
|
var suggestions []string
|
|
// localSettings := config.DefaultLocalSettings()
|
|
var optionVal interface{}
|
|
for k, option := range config.GlobalSettings {
|
|
if k == inputOpt {
|
|
optionVal = option
|
|
}
|
|
}
|
|
// for k, option := range localSettings {
|
|
// if k == inputOpt {
|
|
// optionVal = option
|
|
// }
|
|
// }
|
|
|
|
switch optionVal.(type) {
|
|
case bool:
|
|
if strings.HasPrefix("on", input) {
|
|
suggestions = append(suggestions, "on")
|
|
} else if strings.HasPrefix("true", input) {
|
|
suggestions = append(suggestions, "true")
|
|
}
|
|
if strings.HasPrefix("off", input) {
|
|
suggestions = append(suggestions, "off")
|
|
} else if strings.HasPrefix("false", input) {
|
|
suggestions = append(suggestions, "false")
|
|
}
|
|
case string:
|
|
switch inputOpt {
|
|
case "colorscheme":
|
|
_, suggestions = colorschemeComplete(input)
|
|
case "filetype":
|
|
_, suggestions = filetypeComplete(input)
|
|
case "sucmd":
|
|
if strings.HasPrefix("sudo", input) {
|
|
suggestions = append(suggestions, "sudo")
|
|
}
|
|
if strings.HasPrefix("doas", input) {
|
|
suggestions = append(suggestions, "doas")
|
|
}
|
|
default:
|
|
if choices, ok := config.OptionChoices[inputOpt]; ok {
|
|
for _, choice := range choices {
|
|
if strings.HasPrefix(choice, input) {
|
|
suggestions = append(suggestions, choice)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sort.Strings(suggestions)
|
|
|
|
completions := make([]string, len(suggestions))
|
|
for i := range suggestions {
|
|
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
}
|
|
return completions, suggestions
|
|
}
|
|
|
|
// PluginCmdComplete autocompletes the plugin command
|
|
func PluginCmdComplete(b *buffer.Buffer) ([]string, []string) {
|
|
c := b.GetActiveCursor()
|
|
input, argstart := b.GetArg()
|
|
|
|
var suggestions []string
|
|
for _, cmd := range PluginCmds {
|
|
if strings.HasPrefix(cmd, input) {
|
|
suggestions = append(suggestions, cmd)
|
|
}
|
|
}
|
|
|
|
sort.Strings(suggestions)
|
|
completions := make([]string, len(suggestions))
|
|
for i := range suggestions {
|
|
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
}
|
|
return completions, suggestions
|
|
}
|
|
|
|
// PluginComplete completes values for the plugin command
|
|
func PluginComplete(b *buffer.Buffer) ([]string, []string) {
|
|
c := b.GetActiveCursor()
|
|
l := b.LineBytes(c.Y)
|
|
l = util.SliceStart(l, c.X)
|
|
input, argstart := b.GetArg()
|
|
|
|
completeValue := false
|
|
args := bytes.Split(l, []byte{' '})
|
|
if len(args) >= 2 {
|
|
for _, cmd := range PluginCmds {
|
|
if cmd == string(args[len(args)-2]) {
|
|
completeValue = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !completeValue {
|
|
return PluginCmdComplete(b)
|
|
}
|
|
|
|
var suggestions []string
|
|
for _, pl := range config.Plugins {
|
|
if strings.HasPrefix(pl.Name, input) {
|
|
suggestions = append(suggestions, pl.Name)
|
|
}
|
|
}
|
|
sort.Strings(suggestions)
|
|
|
|
completions := make([]string, len(suggestions))
|
|
for i := range suggestions {
|
|
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
}
|
|
return completions, suggestions
|
|
}
|
|
|
|
// PluginNameComplete completes with the names of loaded plugins
|
|
// func PluginNameComplete(b *buffer.Buffer) ([]string, []string) {
|
|
// c := b.GetActiveCursor()
|
|
// input, argstart := buffer.GetArg(b)
|
|
//
|
|
// var suggestions []string
|
|
// for _, pp := range config.GetAllPluginPackages(nil) {
|
|
// if strings.HasPrefix(pp.Name, input) {
|
|
// suggestions = append(suggestions, pp.Name)
|
|
// }
|
|
// }
|
|
//
|
|
// sort.Strings(suggestions)
|
|
// completions := make([]string, len(suggestions))
|
|
// for i := range suggestions {
|
|
// completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
|
|
// }
|
|
// return completions, suggestions
|
|
// }
|
|
|
|
// // MakeCompletion registers a function from a plugin for autocomplete commands
|
|
// func MakeCompletion(function string) Completion {
|
|
// pluginCompletions = append(pluginCompletions, LuaFunctionComplete(function))
|
|
// return Completion(-len(pluginCompletions))
|
|
// }
|