/
command.go
158 lines (142 loc) · 4.28 KB
/
command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package ssh
import (
"fmt"
"github.com/LogicalOverflow/music-sync/playback"
"github.com/LogicalOverflow/music-sync/util"
"os"
"path/filepath"
"sort"
"strings"
)
var commands = make([]Command, 0)
type commandsByName []Command
func (c commandsByName) Len() int { return len(c) }
func (c commandsByName) Less(i int, j int) bool { return strings.Compare(c[i].Name, c[j].Name) < 0 }
func (c commandsByName) Swap(i int, j int) { c[i], c[j] = c[j], c[i] }
// RegisterCommand registers a command to allow its use from ssh control interface
func RegisterCommand(c Command) {
commands = append(commands, c)
sort.Sort(commandsByName(commands))
}
// Command describes a ssh command
type Command struct {
Name string // Name is the name of the command, which is used to access it from the terminal
Usage string // Usage contains usage information for the command
Info string // Info contains information about what the command does
// Exec runs the command. It is passed the arguments as a string slice.
// If it returns false, a usage message is printed, otherwise the returned string is printed
ExecFunc func(args []string) (string, bool)
// OptionsFunc (optional) is used for auto completion. It is passed a prefix and the number of the argument and should
// return all possible completion options
OptionsFunc func(prefix string, arg int) []string
}
// Exec executes ExecFunc
func (command Command) Exec(args []string) (string, bool) {
return command.ExecFunc(args)
}
// Options executes OptionsFunc (if provided) or returns []string{}
func (command Command) Options(prefix string, arg int) []string {
if command.OptionsFunc == nil {
return []string{}
}
return command.OptionsFunc(prefix, arg)
}
// GetName returns the printable name of the command
func (command Command) GetName() string {
return command.Name
}
func (command Command) usage() string {
if command.Usage == "" {
return fmt.Sprintf("No usage information for command '%s'", command.Name)
}
return "Usage: " + command.Name + " " + command.Usage
}
func commandByName(name string) *Command {
for _, c := range commands {
if c.Name == name {
return &c
}
}
return nil
}
var helpCommand = Command{
Name: "help",
Usage: "[command name]",
Info: "retrieves help for a command",
ExecFunc: func(args []string) (string, bool) {
if len(args) == 0 {
usages := make([]string, 0, len(commands))
for _, c := range commands {
usages = append(usages, fmt.Sprintf("%-15s %s", c.Name, c.Info))
}
usages = append(usages,
fmt.Sprintf("%-15s %s", "clear", "Clears the terminal"),
fmt.Sprintf("%-15s %s", "exit", "Closes the connection"),
)
return strings.Join(usages, "\n"), true
}
var target *Command
for _, c := range commands {
if c.Name == args[0] {
target = &Command{}
*target = c
}
}
if target == nil {
switch args[0] {
case "clear":
return "clear: Clears the terminal\nclear", true
case "exit":
return "exit: Closes the connection\nexit", true
default:
return fmt.Sprintf("Command '%s' does not exist.", args[0]), true
}
}
return target.Name + ": " + target.Info + "\n" + target.usage(), true
},
OptionsFunc: func(prefix string, arg int) []string {
if arg != 0 {
return []string{}
}
options := []string{"clear", "exit"}
for _, c := range commands {
if strings.HasPrefix(c.Name, prefix) {
options = append(options, c.Name)
}
}
return options
},
}
var lsCommand = Command{
Name: "ls",
Usage: "[sub directory]",
Info: "lists all songs in the music (sub) directory",
ExecFunc: func(args []string) (string, bool) {
subDir := ""
if 0 < len(args) {
subDir = args[0]
}
songs := util.FilterSongs(util.ListAllFiles(playback.AudioDir, subDir))
return strings.Join(songs, "\n"), true
},
OptionsFunc: func(prefix string, arg int) []string {
if arg != 0 {
return []string{}
}
subDirs := util.ListAllSubDirs(playback.AudioDir)
options := make([]string, 0, len(subDirs))
for _, subDir := range subDirs {
if !strings.HasPrefix(subDir, prefix) {
continue
}
if d, f := filepath.Split(subDir[len(prefix):]); d == "" && f == subDir[len(prefix):] {
options = append(options, subDir+string(os.PathSeparator))
}
}
return options
},
}
func init() {
RegisterCommand(helpCommand)
RegisterCommand(lsCommand)
}