mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-29 22:27:13 +09:00
Infobar history
This commit is contained in:
@@ -560,7 +560,7 @@ func (h *BufHandler) SaveAs() bool {
|
||||
|
||||
// Find opens a prompt and searches forward for the input
|
||||
func (h *BufHandler) Find() bool {
|
||||
InfoBar.Prompt("Find: ", "", func(resp string) {
|
||||
InfoBar.Prompt("Find: ", "", "Find", func(resp string) {
|
||||
// Event callback
|
||||
match, found, _ := h.Buf.FindNext(resp, h.Cursor.Loc, true)
|
||||
if found {
|
||||
@@ -802,7 +802,7 @@ func (h *BufHandler) SelectAll() bool {
|
||||
|
||||
// OpenFile opens a new file in the buffer
|
||||
func (h *BufHandler) OpenFile() bool {
|
||||
InfoBar.Prompt("> ", "open ", nil, func(resp string, canceled bool) {
|
||||
InfoBar.Prompt("> ", "open ", "Open", nil, func(resp string, canceled bool) {
|
||||
if !canceled {
|
||||
HandleCommand(resp)
|
||||
}
|
||||
@@ -966,7 +966,7 @@ func (h *BufHandler) ShellMode() bool {
|
||||
|
||||
// CommandMode lets the user enter a command
|
||||
func (h *BufHandler) CommandMode() bool {
|
||||
InfoBar.Prompt("> ", "", nil, func(resp string, canceled bool) {
|
||||
InfoBar.Prompt("> ", "", "Command", nil, func(resp string, canceled bool) {
|
||||
if !canceled {
|
||||
HandleCommand(resp)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package action
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/zyedidia/micro/cmd/micro/info"
|
||||
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
||||
"github.com/zyedidia/micro/cmd/micro/util"
|
||||
)
|
||||
@@ -11,13 +10,13 @@ import (
|
||||
// A Command contains an action (a function to call) as well as information about how to autocomplete the command
|
||||
type Command struct {
|
||||
action func([]string)
|
||||
completions []info.Completion
|
||||
completions []Completion
|
||||
}
|
||||
|
||||
// A StrCommand is similar to a command but keeps the name of the action
|
||||
type StrCommand struct {
|
||||
action string
|
||||
completions []info.Completion
|
||||
completions []Completion
|
||||
}
|
||||
|
||||
var commands map[string]Command
|
||||
@@ -71,7 +70,7 @@ func parseCommands(userCommands map[string]StrCommand) {
|
||||
|
||||
// MakeCommand is a function to easily create new commands
|
||||
// This can be called by plugins in Lua so that plugins can define their own commands
|
||||
func MakeCommand(name, function string, completions ...info.Completion) {
|
||||
func MakeCommand(name, function string, completions ...Completion) {
|
||||
action := commandActions[function]
|
||||
// if _, ok := commandActions[function]; !ok {
|
||||
// If the user seems to be binding a function that doesn't exist
|
||||
@@ -85,32 +84,32 @@ func MakeCommand(name, function string, completions ...info.Completion) {
|
||||
// DefaultCommands returns a map containing micro's default commands
|
||||
func DefaultCommands() map[string]StrCommand {
|
||||
return map[string]StrCommand{
|
||||
"set": {"Set", []info.Completion{info.OptionCompletion, info.OptionValueCompletion}},
|
||||
"setlocal": {"SetLocal", []info.Completion{info.OptionCompletion, info.OptionValueCompletion}},
|
||||
"show": {"Show", []info.Completion{info.OptionCompletion, info.NoCompletion}},
|
||||
"showkey": {"ShowKey", []info.Completion{info.NoCompletion}},
|
||||
"bind": {"Bind", []info.Completion{info.NoCompletion}},
|
||||
"run": {"Run", []info.Completion{info.NoCompletion}},
|
||||
"quit": {"Quit", []info.Completion{info.NoCompletion}},
|
||||
"save": {"Save", []info.Completion{info.NoCompletion}},
|
||||
"replace": {"Replace", []info.Completion{info.NoCompletion}},
|
||||
"replaceall": {"ReplaceAll", []info.Completion{info.NoCompletion}},
|
||||
"vsplit": {"VSplit", []info.Completion{info.FileCompletion, info.NoCompletion}},
|
||||
"hsplit": {"HSplit", []info.Completion{info.FileCompletion, info.NoCompletion}},
|
||||
"tab": {"Tab", []info.Completion{info.FileCompletion, info.NoCompletion}},
|
||||
"help": {"Help", []info.Completion{info.HelpCompletion, info.NoCompletion}},
|
||||
"eval": {"Eval", []info.Completion{info.NoCompletion}},
|
||||
"log": {"ToggleLog", []info.Completion{info.NoCompletion}},
|
||||
"plugin": {"Plugin", []info.Completion{info.PluginCmdCompletion, info.PluginNameCompletion}},
|
||||
"reload": {"Reload", []info.Completion{info.NoCompletion}},
|
||||
"cd": {"Cd", []info.Completion{info.FileCompletion}},
|
||||
"pwd": {"Pwd", []info.Completion{info.NoCompletion}},
|
||||
"open": {"Open", []info.Completion{info.FileCompletion}},
|
||||
"tabswitch": {"TabSwitch", []info.Completion{info.NoCompletion}},
|
||||
"term": {"Term", []info.Completion{info.NoCompletion}},
|
||||
"memusage": {"MemUsage", []info.Completion{info.NoCompletion}},
|
||||
"retab": {"Retab", []info.Completion{info.NoCompletion}},
|
||||
"raw": {"Raw", []info.Completion{info.NoCompletion}},
|
||||
"set": {"Set", []Completion{OptionCompletion, OptionValueCompletion}},
|
||||
"setlocal": {"SetLocal", []Completion{OptionCompletion, OptionValueCompletion}},
|
||||
"show": {"Show", []Completion{OptionCompletion, NoCompletion}},
|
||||
"showkey": {"ShowKey", []Completion{NoCompletion}},
|
||||
"bind": {"Bind", []Completion{NoCompletion}},
|
||||
"run": {"Run", []Completion{NoCompletion}},
|
||||
"quit": {"Quit", []Completion{NoCompletion}},
|
||||
"save": {"Save", []Completion{NoCompletion}},
|
||||
"replace": {"Replace", []Completion{NoCompletion}},
|
||||
"replaceall": {"ReplaceAll", []Completion{NoCompletion}},
|
||||
"vsplit": {"VSplit", []Completion{FileCompletion, NoCompletion}},
|
||||
"hsplit": {"HSplit", []Completion{FileCompletion, NoCompletion}},
|
||||
"tab": {"Tab", []Completion{FileCompletion, NoCompletion}},
|
||||
"help": {"Help", []Completion{HelpCompletion, NoCompletion}},
|
||||
"eval": {"Eval", []Completion{NoCompletion}},
|
||||
"log": {"ToggleLog", []Completion{NoCompletion}},
|
||||
"plugin": {"Plugin", []Completion{PluginCmdCompletion, PluginNameCompletion}},
|
||||
"reload": {"Reload", []Completion{NoCompletion}},
|
||||
"cd": {"Cd", []Completion{FileCompletion}},
|
||||
"pwd": {"Pwd", []Completion{NoCompletion}},
|
||||
"open": {"Open", []Completion{FileCompletion}},
|
||||
"tabswitch": {"TabSwitch", []Completion{NoCompletion}},
|
||||
"term": {"Term", []Completion{NoCompletion}},
|
||||
"memusage": {"MemUsage", []Completion{NoCompletion}},
|
||||
"retab": {"Retab", []Completion{NoCompletion}},
|
||||
"raw": {"Raw", []Completion{NoCompletion}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +118,7 @@ func DefaultCommands() map[string]StrCommand {
|
||||
// enter
|
||||
func CommandEditAction(prompt string) BufKeyAction {
|
||||
return func(h *BufHandler) bool {
|
||||
InfoBar.Prompt("> ", prompt, nil, func(resp string, canceled bool) {
|
||||
InfoBar.Prompt("> ", prompt, "Command", nil, func(resp string, canceled bool) {
|
||||
if !canceled {
|
||||
HandleCommand(resp)
|
||||
}
|
||||
|
||||
266
cmd/micro/action/infocomplete.go
Normal file
266
cmd/micro/action/infocomplete.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/zyedidia/micro/cmd/micro/config"
|
||||
"github.com/zyedidia/micro/cmd/micro/util"
|
||||
)
|
||||
|
||||
// Completion represents a type of completion
|
||||
type Completion int
|
||||
|
||||
const (
|
||||
NoCompletion Completion = iota
|
||||
FileCompletion
|
||||
CommandCompletion
|
||||
HelpCompletion
|
||||
OptionCompletion
|
||||
PluginCmdCompletion
|
||||
PluginNameCompletion
|
||||
OptionValueCompletion
|
||||
)
|
||||
|
||||
var pluginCompletions []func(string) []string
|
||||
|
||||
// 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`.
|
||||
|
||||
// FileComplete autocompletes filenames
|
||||
func FileComplete(input string) (string, []string) {
|
||||
var sep string = string(os.PathSeparator)
|
||||
dirs := strings.Split(input, sep)
|
||||
|
||||
var files []os.FileInfo
|
||||
var err error
|
||||
if len(dirs) > 1 {
|
||||
directories := strings.Join(dirs[:len(dirs)-1], sep) + sep
|
||||
|
||||
directories, _ = util.ReplaceHome(directories)
|
||||
files, err = ioutil.ReadDir(directories)
|
||||
} else {
|
||||
files, err = ioutil.ReadDir(".")
|
||||
}
|
||||
|
||||
var suggestions []string
|
||||
if err != nil {
|
||||
return "", suggestions
|
||||
}
|
||||
for _, f := range files {
|
||||
name := f.Name()
|
||||
if f.IsDir() {
|
||||
name += sep
|
||||
}
|
||||
if strings.HasPrefix(name, dirs[len(dirs)-1]) {
|
||||
suggestions = append(suggestions, name)
|
||||
}
|
||||
}
|
||||
|
||||
var chosen string
|
||||
if len(suggestions) == 1 {
|
||||
if len(dirs) > 1 {
|
||||
chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep + suggestions[0]
|
||||
} else {
|
||||
chosen = suggestions[0]
|
||||
}
|
||||
} else {
|
||||
if len(dirs) > 1 {
|
||||
chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep
|
||||
}
|
||||
}
|
||||
|
||||
return chosen, suggestions
|
||||
}
|
||||
|
||||
// CommandComplete autocompletes commands
|
||||
func CommandComplete(input string) (string, []string) {
|
||||
var suggestions []string
|
||||
for cmd := range commands {
|
||||
if strings.HasPrefix(cmd, input) {
|
||||
suggestions = append(suggestions, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
var chosen string
|
||||
if len(suggestions) == 1 {
|
||||
chosen = suggestions[0]
|
||||
}
|
||||
return chosen, suggestions
|
||||
}
|
||||
|
||||
// HelpComplete autocompletes help topics
|
||||
func HelpComplete(input string) (string, []string) {
|
||||
var suggestions []string
|
||||
|
||||
for _, file := range config.ListRuntimeFiles(config.RTHelp) {
|
||||
topic := file.Name()
|
||||
if strings.HasPrefix(topic, input) {
|
||||
suggestions = append(suggestions, topic)
|
||||
}
|
||||
}
|
||||
|
||||
var chosen string
|
||||
if len(suggestions) == 1 {
|
||||
chosen = suggestions[0]
|
||||
}
|
||||
return chosen, suggestions
|
||||
}
|
||||
|
||||
// ColorschemeComplete tab-completes names of colorschemes.
|
||||
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
|
||||
}
|
||||
|
||||
func contains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// OptionComplete autocompletes options
|
||||
func OptionComplete(input string) (string, []string) {
|
||||
var suggestions []string
|
||||
localSettings := config.DefaultLocalSettings()
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
var chosen string
|
||||
if len(suggestions) == 1 {
|
||||
chosen = suggestions[0]
|
||||
}
|
||||
return chosen, suggestions
|
||||
}
|
||||
|
||||
// OptionValueComplete completes values for various options
|
||||
func OptionValueComplete(inputOpt, input string) (string, []string) {
|
||||
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 "fileformat":
|
||||
if strings.HasPrefix("unix", input) {
|
||||
suggestions = append(suggestions, "unix")
|
||||
}
|
||||
if strings.HasPrefix("dos", input) {
|
||||
suggestions = append(suggestions, "dos")
|
||||
}
|
||||
case "sucmd":
|
||||
if strings.HasPrefix("sudo", input) {
|
||||
suggestions = append(suggestions, "sudo")
|
||||
}
|
||||
if strings.HasPrefix("doas", input) {
|
||||
suggestions = append(suggestions, "doas")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var chosen string
|
||||
if len(suggestions) == 1 {
|
||||
chosen = suggestions[0]
|
||||
}
|
||||
return chosen, 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))
|
||||
// }
|
||||
//
|
||||
// // PluginComplete autocompletes from plugin function
|
||||
// func PluginComplete(complete Completion, input string) (chosen string, suggestions []string) {
|
||||
// idx := int(-complete) - 1
|
||||
//
|
||||
// if len(pluginCompletions) <= idx {
|
||||
// return "", nil
|
||||
// }
|
||||
// suggestions = pluginCompletions[idx](input)
|
||||
//
|
||||
// if len(suggestions) == 1 {
|
||||
// chosen = suggestions[0]
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // PluginCmdComplete completes with possible choices for the `> plugin` command
|
||||
// func PluginCmdComplete(input string) (chosen string, suggestions []string) {
|
||||
// for _, cmd := range []string{"install", "remove", "search", "update", "list"} {
|
||||
// if strings.HasPrefix(cmd, input) {
|
||||
// suggestions = append(suggestions, cmd)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if len(suggestions) == 1 {
|
||||
// chosen = suggestions[0]
|
||||
// }
|
||||
// return chosen, suggestions
|
||||
// }
|
||||
//
|
||||
// // PluginnameComplete completes with the names of loaded plugins
|
||||
// func PluginNameComplete(input string) (chosen string, suggestions []string) {
|
||||
// for _, pp := range GetAllPluginPackages() {
|
||||
// if strings.HasPrefix(pp.Name, input) {
|
||||
// suggestions = append(suggestions, pp.Name)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if len(suggestions) == 1 {
|
||||
// chosen = suggestions[0]
|
||||
// }
|
||||
// return chosen, suggestions
|
||||
// }
|
||||
@@ -35,6 +35,15 @@ func (h *InfoHandler) HandleEvent(event tcell.Event) {
|
||||
done := h.DoKeyEvent(ke)
|
||||
if !done && e.Key() == tcell.KeyRune {
|
||||
h.DoRuneInsert(e.Rune())
|
||||
done = true
|
||||
}
|
||||
if done && h.HasPrompt {
|
||||
resp := strings.TrimSpace(string(h.LineBytes(0)))
|
||||
hist := h.History[h.PromptType]
|
||||
hist[h.HistoryNum] = resp
|
||||
if h.EventCallback != nil {
|
||||
h.EventCallback(resp)
|
||||
}
|
||||
}
|
||||
case *tcell.EventMouse:
|
||||
h.BufHandler.HandleEvent(event)
|
||||
@@ -61,19 +70,9 @@ func (h *InfoHandler) DoKeyEvent(e KeyEvent) bool {
|
||||
done = action(h.BufHandler)
|
||||
}
|
||||
}
|
||||
if done && h.EventCallback != nil {
|
||||
h.EventCallback(strings.TrimSpace(string(h.LineBytes(0))))
|
||||
}
|
||||
return done
|
||||
}
|
||||
|
||||
func (h *InfoHandler) DoRuneInsert(r rune) {
|
||||
h.BufHandler.DoRuneInsert(r)
|
||||
if h.EventCallback != nil {
|
||||
h.EventCallback(strings.TrimSpace(string(h.LineBytes(0))))
|
||||
}
|
||||
}
|
||||
|
||||
// InfoNones is a list of actions that should have no effect when executed
|
||||
// by an infohandler
|
||||
var InfoNones = []string{
|
||||
@@ -136,10 +135,10 @@ var InfoOverrides = map[string]InfoKeyAction{
|
||||
}
|
||||
|
||||
func (h *InfoHandler) CursorUp() {
|
||||
// TODO: history
|
||||
h.UpHistory(h.History[h.PromptType])
|
||||
}
|
||||
func (h *InfoHandler) CursorDown() {
|
||||
// TODO: history
|
||||
h.DownHistory(h.History[h.PromptType])
|
||||
}
|
||||
func (h *InfoHandler) InsertTab() {
|
||||
// TODO: autocomplete
|
||||
|
||||
Reference in New Issue
Block a user