]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/command.go
Go plugin should disable tabstospaces if the file is go
[micro.git] / cmd / micro / command.go
index 2d389f9e67a15550c0732d3828d0de7eeec43e85..b41a3db4748920cbaacf7902524817d3c6c585e8 100644 (file)
@@ -2,15 +2,27 @@ package main
 
 import (
        "bytes"
+       "io/ioutil"
        "os"
        "os/exec"
        "os/signal"
        "regexp"
        "strings"
-       "strconv"
+
+       "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,
@@ -19,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
@@ -45,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
@@ -88,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
@@ -149,7 +254,7 @@ func Replace(args []string) {
                if match == nil {
                        break
                }
-               found = found + 1
+               found++
                if strings.Contains(flags, "c") {
                        // The 'check' flag was used
                        Search(search, view, true)
@@ -184,12 +289,14 @@ func Replace(args []string) {
                        view.Buf.Replace(FromCharPos(match[0], view.Buf), FromCharPos(match[1], view.Buf), replace)
                }
        }
+       view.Cursor.Relocate()
+
        if found > 1 {
-               messenger.Message("Replaced " + strconv.Itoa(found) + " occurences of " + search)
+               messenger.Message("Replaced ", found, " occurences of ", search)
        } else if found == 1 {
-               messenger.Message("Replaced " + strconv.Itoa(found) + " occurence of " + search)
+               messenger.Message("Replaced ", found, " occurence of ", search)
        } else {
-               messenger.Message("Nothing matched " + search)
+               messenger.Message("Nothing matched ", search)
        }
 }
 
@@ -275,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)
        }
 }