shell_liner.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package shell
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "path"
  7. "regexp"
  8. "strings"
  9. "sort"
  10. "github.com/peterh/liner"
  11. )
  12. var (
  13. line *liner.State
  14. historyPath = path.Join(os.TempDir(), "weed-shell")
  15. )
  16. func RunShell(options ShellOptions) {
  17. line = liner.NewLiner()
  18. defer line.Close()
  19. line.SetCtrlCAborts(true)
  20. setCompletionHandler()
  21. loadHistory()
  22. defer saveHistory()
  23. reg, _ := regexp.Compile(`'.*?'|".*?"|\S+`)
  24. commandEnv := NewCommandEnv(options)
  25. go commandEnv.MasterClient.KeepConnectedToMaster()
  26. commandEnv.MasterClient.WaitUntilConnected()
  27. for {
  28. cmd, err := line.Prompt("> ")
  29. if err != nil {
  30. if err != io.EOF {
  31. fmt.Printf("%v\n", err)
  32. }
  33. return
  34. }
  35. cmds := reg.FindAllString(cmd, -1)
  36. if len(cmds) == 0 {
  37. continue
  38. } else {
  39. line.AppendHistory(cmd)
  40. args := make([]string, len(cmds[1:]))
  41. for i := range args {
  42. args[i] = strings.Trim(string(cmds[1+i]), "\"'")
  43. }
  44. cmd := strings.ToLower(cmds[0])
  45. if cmd == "help" || cmd == "?" {
  46. printHelp(cmds)
  47. } else if cmd == "exit" || cmd == "quit" {
  48. return
  49. } else {
  50. foundCommand := false
  51. for _, c := range Commands {
  52. if c.Name() == cmd {
  53. if err := c.Do(args, commandEnv, os.Stdout); err != nil {
  54. fmt.Fprintf(os.Stderr, "error: %v\n", err)
  55. }
  56. foundCommand = true
  57. }
  58. }
  59. if !foundCommand {
  60. fmt.Fprintf(os.Stderr, "unknown command: %v\n", cmd)
  61. }
  62. }
  63. }
  64. }
  65. }
  66. func printGenericHelp() {
  67. msg :=
  68. `Type: "help <command>" for help on <command>
  69. `
  70. fmt.Print(msg)
  71. sort.Slice(Commands, func(i, j int) bool {
  72. return strings.Compare(Commands[i].Name(), Commands[j].Name()) < 0
  73. })
  74. for _, c := range Commands {
  75. helpTexts := strings.SplitN(c.Help(), "\n", 2)
  76. fmt.Printf(" %-30s\t# %s \n", c.Name(), helpTexts[0])
  77. }
  78. }
  79. func printHelp(cmds []string) {
  80. args := cmds[1:]
  81. if len(args) == 0 {
  82. printGenericHelp()
  83. } else if len(args) > 1 {
  84. fmt.Println()
  85. } else {
  86. cmd := strings.ToLower(args[0])
  87. sort.Slice(Commands, func(i, j int) bool {
  88. return strings.Compare(Commands[i].Name(), Commands[j].Name()) < 0
  89. })
  90. for _, c := range Commands {
  91. if c.Name() == cmd {
  92. fmt.Printf(" %s\t# %s\n", c.Name(), c.Help())
  93. }
  94. }
  95. }
  96. }
  97. func setCompletionHandler() {
  98. line.SetCompleter(func(line string) (c []string) {
  99. for _, i := range Commands {
  100. if strings.HasPrefix(i.Name(), strings.ToLower(line)) {
  101. c = append(c, i.Name())
  102. }
  103. }
  104. return
  105. })
  106. }
  107. func loadHistory() {
  108. if f, err := os.Open(historyPath); err == nil {
  109. line.ReadHistory(f)
  110. f.Close()
  111. }
  112. }
  113. func saveHistory() {
  114. if f, err := os.Create(historyPath); err != nil {
  115. fmt.Printf("Error writing history file: %v\n", err)
  116. } else {
  117. line.WriteHistory(f)
  118. f.Close()
  119. }
  120. }