main.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "github.com/spf13/cobra"
  7. "netdome.biz/paul/qmk-rgb/internal/device"
  8. )
  9. // version is set at build time via -ldflags.
  10. var version = "dev"
  11. // Group IDs for the root help. They name a group in the help output and say
  12. // nothing else: no behaviour hangs off them.
  13. const (
  14. groupLighting = "lighting"
  15. groupProfile = "profile"
  16. groupKeyboard = "keyboard"
  17. )
  18. var (
  19. targetDevice string
  20. targetZone string
  21. )
  22. func newRootCommand() *cobra.Command {
  23. cmd := &cobra.Command{
  24. Use: "qmk-rgb-tool",
  25. Short: "QMK RGB CLI — control QMK keyboard lighting",
  26. SilenceErrors: true,
  27. SilenceUsage: true,
  28. }
  29. // The commands are grouped because fifteen of them in one flat list is where
  30. // a user starts reading the help to find a command and gives up. A group says
  31. // what a command is for, and a command in none of them lands under
  32. // "Additional Commands" where the grouping says nothing.
  33. cmd.AddGroup(
  34. &cobra.Group{ID: groupLighting, Title: "Lighting Commands:"},
  35. &cobra.Group{ID: groupProfile, Title: "Profile Commands:"},
  36. &cobra.Group{ID: groupKeyboard, Title: "Keyboard Commands:"},
  37. )
  38. cmd.PersistentFlags().StringVar(&targetDevice, "device", "", "Keyboard number as printed by 'keyboard info', starting at 1")
  39. cmd.PersistentFlags().StringVar(&targetZone, "zone", "", "RGB lighting channel: backlight, rgblight, rgb_matrix, audio or led_matrix, or the name this keyboard's definition gives it")
  40. cmd.PersistentFlags().StringVar(&definitionFlag, "definition", "", "VIA definition file to read effect names from, instead of the one in the data directory")
  41. cmd.PersistentFlags().BoolVar(&jsonOutput, "json", false, "Print JSON instead of text")
  42. return cmd
  43. }
  44. var rootCmd = newRootCommand()
  45. func Execute() {
  46. if err := rootCmd.Execute(); err != nil {
  47. fmt.Fprintf(os.Stderr, "Error: %v\n", err)
  48. os.Exit(1)
  49. }
  50. }
  51. func main() {
  52. Execute()
  53. }
  54. var keyboardCmd = &cobra.Command{
  55. Use: "keyboard",
  56. Short: "Keyboard management commands",
  57. GroupID: groupKeyboard,
  58. }
  59. // inGroup places a command in one of the root help's groups.
  60. func inGroup(cmd *cobra.Command, group string) *cobra.Command {
  61. cmd.GroupID = group
  62. return cmd
  63. }
  64. // discoverAll is a seam for tests.
  65. var discoverAll = device.DiscoverAll
  66. // runKeyboardInfo writes the connected QMK keyboards, as text unless --json
  67. // asks otherwise. The 1-based index that --device accepts is in the "index"
  68. // field, so the machine shape emits no banner alongside it. Whether a keyboard
  69. // has effect names is reported per keyboard, because it differs: one board may
  70. // have a definition and the next may not.
  71. func runKeyboardInfo(out io.Writer) error {
  72. devices, err := discoverAll()
  73. if err != nil {
  74. return err
  75. }
  76. if devices == nil {
  77. devices = []device.Device{}
  78. }
  79. lines := describeDevices(devices)
  80. if !jsonOutput {
  81. return printKeyboardInfoText(out, lines)
  82. }
  83. type info struct {
  84. Devices []keyboardLine `json:"devices"`
  85. Total int `json:"total"`
  86. }
  87. return encodeJSON(out, info{Devices: lines, Total: len(lines)})
  88. }
  89. var keyboardInfoCmd = &cobra.Command{
  90. Use: "info",
  91. Short: "Discover connected QMK keyboards",
  92. Long: "Scan for connected QMK keyboards and print device info as JSON.\n" +
  93. "Each device carries the 1-based index that --device accepts.",
  94. Args: cobra.NoArgs,
  95. RunE: func(cmd *cobra.Command, args []string) error {
  96. return runKeyboardInfo(cmd.OutOrStdout())
  97. },
  98. }
  99. func init() {
  100. registerCommands(rootCmd)
  101. rootCmd.Version = version
  102. rootCmd.SetVersionTemplate(" qmk-rgb-tool {{.Version}}\n")
  103. }
  104. // registerCommands adds every command to the root, each in the group the help
  105. // output lists it under. It is a function of its own so that a test can build the
  106. // same tree the binary runs and check the grouping is real, rather than repeating
  107. // a list that could fall behind the one that ships.
  108. func registerCommands(root *cobra.Command) {
  109. keyboardCmd.AddCommand(keyboardInfoCmd)
  110. root.AddCommand(
  111. inGroup(NewEnableCmd(), groupLighting),
  112. inGroup(NewDisableCmd(), groupLighting),
  113. inGroup(NewInfoCmd(), groupLighting),
  114. inGroup(NewEffectCmd(), groupLighting),
  115. inGroup(NewBrightnessCmd(), groupLighting),
  116. inGroup(NewSpeedCmd(), groupLighting),
  117. inGroup(NewColorCmd(), groupLighting),
  118. inGroup(NewModeCmd(), groupLighting),
  119. inGroup(NewProfileSaveCmd(), groupProfile),
  120. inGroup(NewProfileLoadCmd(), groupProfile),
  121. inGroup(NewProfileListCmd(), groupProfile),
  122. inGroup(NewProfileDeleteCmd(), groupProfile),
  123. inGroup(NewDefinitionCmd(), groupKeyboard),
  124. inGroup(keyboardCmd, groupKeyboard),
  125. )
  126. }