X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=cmd%2Fmicro%2Fcommand.go;h=b41a3db4748920cbaacf7902524817d3c6c585e8;hb=f9cb99b35fa36099ac254e129e2668ada6a5034f;hp=5cabce01b13e4888e4f3916b6d10c98bdcb9a4d2;hpb=40affa56c74eebbd940a04b41e54eca3904962b5;p=micro.git diff --git a/cmd/micro/command.go b/cmd/micro/command.go index 5cabce01..b41a3db4 100644 --- a/cmd/micro/command.go +++ b/cmd/micro/command.go @@ -2,14 +2,27 @@ package main import ( "bytes" + "io/ioutil" "os" "os/exec" "os/signal" "regexp" "strings" + + "github.com/mitchellh/go-homedir" ) -var commands map[string]func([]string) +type Command struct { + action func([]string) + completions []Completion +} + +type StrCommand struct { + action string + completions []Completion +} + +var commands map[string]Command var commandActions = map[string]func([]string){ "Set": Set, @@ -18,25 +31,29 @@ var commandActions = map[string]func([]string){ "Quit": Quit, "Save": Save, "Replace": Replace, + "VSplit": VSplit, + "HSplit": HSplit, + "Tab": NewTab, + "Help": Help, } // InitCommands initializes the default commands func InitCommands() { - commands = make(map[string]func([]string)) + commands = make(map[string]Command) defaults := DefaultCommands() parseCommands(defaults) } -func parseCommands(userCommands map[string]string) { +func parseCommands(userCommands map[string]StrCommand) { for k, v := range userCommands { - MakeCommand(k, v) + MakeCommand(k, v.action, v.completions...) } } // 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) { +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 @@ -44,29 +61,118 @@ func MakeCommand(name, function string) { action = LuaFunctionCommand(function) } - commands[name] = action + commands[name] = Command{action, completions} } // DefaultCommands returns a map containing micro's default commands -func DefaultCommands() map[string]string { - return map[string]string{ - "set": "Set", - "bind": "Bind", - "run": "Run", - "quit": "Quit", - "save": "Save", - "replace": "Replace", +func DefaultCommands() map[string]StrCommand { + return map[string]StrCommand{ + "set": StrCommand{"Set", []Completion{OptionCompletion, NoCompletion}}, + "bind": StrCommand{"Bind", []Completion{NoCompletion}}, + "run": StrCommand{"Run", []Completion{NoCompletion}}, + "quit": StrCommand{"Quit", []Completion{NoCompletion}}, + "save": StrCommand{"Save", []Completion{NoCompletion}}, + "replace": StrCommand{"Replace", []Completion{NoCompletion}}, + "vsplit": StrCommand{"VSplit", []Completion{FileCompletion, NoCompletion}}, + "hsplit": StrCommand{"HSplit", []Completion{FileCompletion, NoCompletion}}, + "tab": StrCommand{"Tab", []Completion{FileCompletion, NoCompletion}}, + "help": StrCommand{"Help", []Completion{HelpCompletion, NoCompletion}}, + } +} + +// Help tries to open the given help page in a horizontal split +func Help(args []string) { + if len(args) < 1 { + // Open the default help if the user just typed "> help" + CurView().openHelp("help") + } else { + helpPage := args[0] + if _, ok := helpPages[helpPage]; ok { + CurView().openHelp(helpPage) + } else { + messenger.Error("Sorry, no help for ", helpPage) + } + } +} + +// VSplit opens a vertical split with file given in the first argument +// If no file is given, it opens an empty buffer in a new split +func VSplit(args []string) { + if len(args) == 0 { + CurView().VSplit(NewBuffer([]byte{}, "")) + } else { + filename := args[0] + home, _ := homedir.Dir() + filename = strings.Replace(filename, "~", home, 1) + file, err := ioutil.ReadFile(filename) + + var buf *Buffer + if err != nil { + // File does not exist -- create an empty buffer with that name + buf = NewBuffer([]byte{}, filename) + } else { + buf = NewBuffer(file, filename) + } + CurView().VSplit(buf) + } +} + +// HSplit opens a horizontal split with file given in the first argument +// If no file is given, it opens an empty buffer in a new split +func HSplit(args []string) { + if len(args) == 0 { + CurView().HSplit(NewBuffer([]byte{}, "")) + } else { + filename := args[0] + home, _ := homedir.Dir() + filename = strings.Replace(filename, "~", home, 1) + file, err := ioutil.ReadFile(filename) + + var buf *Buffer + if err != nil { + // File does not exist -- create an empty buffer with that name + buf = NewBuffer([]byte{}, filename) + } else { + buf = NewBuffer(file, filename) + } + CurView().HSplit(buf) + } +} + +// NewTab opens the given file in a new tab +func NewTab(args []string) { + if len(args) == 0 { + CurView().AddTab(true) + } else { + filename := args[0] + home, _ := homedir.Dir() + filename = strings.Replace(filename, "~", home, 1) + file, _ := ioutil.ReadFile(filename) + + tab := NewTabFromView(NewView(NewBuffer(file, filename))) + tab.SetNum(len(tabs)) + tabs = append(tabs, tab) + curTab++ + if len(tabs) == 2 { + for _, t := range tabs { + for _, v := range t.views { + v.ToggleTabbar() + } + } + } } } // Set sets an option func Set(args []string) { - // Set an option and we have to set it for every view - for _, tab := range tabs { - for _, view := range tab.views { - SetOption(view, args) - } + if len(args) < 2 { + return } + + option := strings.TrimSpace(args[0]) + value := strings.TrimSpace(args[1]) + + SetOptionAndSettings(option, value) } // Bind creates a new keybinding @@ -87,13 +193,13 @@ func Run(args []string) { // Quit closes the main view func Quit(args []string) { // Close the main view - CurView().Quit() + CurView().Quit(true) } // Save saves the buffer in the main view func Save(args []string) { // Save the main view - CurView().Save() + CurView().Save(true) } // Replace runs search and replace @@ -142,13 +248,13 @@ func Replace(args []string) { view := CurView() - found := false + found := 0 for { match := regex.FindStringIndex(view.Buf.String()) if match == nil { break } - found = true + found++ if strings.Contains(flags, "c") { // The 'check' flag was used Search(search, view, true) @@ -183,8 +289,14 @@ func Replace(args []string) { view.Buf.Replace(FromCharPos(match[0], view.Buf), FromCharPos(match[1], view.Buf), replace) } } - if !found { - messenger.Message("Nothing matched " + search) + view.Cursor.Relocate() + + if found > 1 { + messenger.Message("Replaced ", found, " occurences of ", search) + } else if found == 1 { + messenger.Message("Replaced ", found, " occurence of ", search) + } else { + messenger.Message("Nothing matched ", search) } } @@ -270,6 +382,6 @@ func HandleCommand(input string) { if _, ok := commands[inputCmd]; !ok { messenger.Error("Unkown command ", inputCmd) } else { - commands[inputCmd](args) + commands[inputCmd].action(args) } }