complete_getopt.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. package edit
  2. import (
  3. "errors"
  4. "fmt"
  5. "strings"
  6. "unicode/utf8"
  7. "src.elv.sh/pkg/eval"
  8. "src.elv.sh/pkg/eval/vals"
  9. "src.elv.sh/pkg/getopt"
  10. "src.elv.sh/pkg/parse"
  11. "src.elv.sh/pkg/ui"
  12. )
  13. func completeGetopt(fm *eval.Frame, vArgs, vOpts, vArgHandlers any) error {
  14. args, err := parseGetoptArgs(vArgs)
  15. if err != nil {
  16. return err
  17. }
  18. opts, err := parseGetoptOptSpecs(vOpts)
  19. if err != nil {
  20. return err
  21. }
  22. argHandlers, variadic, err := parseGetoptArgHandlers(vArgHandlers)
  23. if err != nil {
  24. return err
  25. }
  26. // TODO: Make the Config field configurable
  27. _, parsedArgs, ctx := getopt.Complete(args, opts.opts, getopt.GNU)
  28. out := fm.ValueOutput()
  29. putShortOpt := func(opt *getopt.OptionSpec) error {
  30. c := complexItem{Stem: "-" + string(opt.Short)}
  31. if d, ok := opts.desc[opt]; ok {
  32. if e, ok := opts.argDesc[opt]; ok {
  33. c.Display = ui.T(c.Stem + " " + e + " (" + d + ")")
  34. } else {
  35. c.Display = ui.T(c.Stem + " (" + d + ")")
  36. }
  37. }
  38. return out.Put(c)
  39. }
  40. putLongOpt := func(opt *getopt.OptionSpec) error {
  41. c := complexItem{Stem: "--" + opt.Long}
  42. if d, ok := opts.desc[opt]; ok {
  43. if e, ok := opts.argDesc[opt]; ok {
  44. c.Display = ui.T(c.Stem + " " + e + " (" + d + ")")
  45. } else {
  46. c.Display = ui.T(c.Stem + " (" + d + ")")
  47. }
  48. }
  49. return out.Put(c)
  50. }
  51. call := func(fn eval.Callable, args ...any) error {
  52. return fn.Call(fm, args, eval.NoOpts)
  53. }
  54. switch ctx.Type {
  55. case getopt.OptionOrArgument, getopt.Argument:
  56. // Find argument handler.
  57. var argHandler eval.Callable
  58. if len(parsedArgs) < len(argHandlers) {
  59. argHandler = argHandlers[len(parsedArgs)]
  60. } else if variadic {
  61. argHandler = argHandlers[len(argHandlers)-1]
  62. }
  63. if argHandler != nil {
  64. return call(argHandler, ctx.Text)
  65. }
  66. // TODO(xiaq): Notify that there is no suitable argument completer.
  67. case getopt.AnyOption:
  68. for _, opt := range opts.opts {
  69. if opt.Short != 0 {
  70. err := putShortOpt(opt)
  71. if err != nil {
  72. return err
  73. }
  74. }
  75. if opt.Long != "" {
  76. err := putLongOpt(opt)
  77. if err != nil {
  78. return err
  79. }
  80. }
  81. }
  82. case getopt.LongOption:
  83. for _, opt := range opts.opts {
  84. if opt.Long != "" && strings.HasPrefix(opt.Long, ctx.Text) {
  85. err := putLongOpt(opt)
  86. if err != nil {
  87. return err
  88. }
  89. }
  90. }
  91. case getopt.ChainShortOption:
  92. for _, opt := range opts.opts {
  93. if opt.Short != 0 {
  94. // TODO(xiaq): Loses chained options.
  95. err := putShortOpt(opt)
  96. if err != nil {
  97. return err
  98. }
  99. }
  100. }
  101. case getopt.OptionArgument:
  102. gen := opts.argGenerator[ctx.Option.Spec]
  103. if gen != nil {
  104. return call(gen, ctx.Option.Argument)
  105. }
  106. }
  107. return nil
  108. }
  109. // TODO(xiaq): Simplify most of the parsing below with reflection.
  110. func parseGetoptArgs(v any) ([]string, error) {
  111. var args []string
  112. var err error
  113. errIterate := vals.Iterate(v, func(v any) bool {
  114. arg, ok := v.(string)
  115. if !ok {
  116. err = fmt.Errorf("arg should be string, got %s", vals.Kind(v))
  117. return false
  118. }
  119. args = append(args, arg)
  120. return true
  121. })
  122. if errIterate != nil {
  123. err = errIterate
  124. }
  125. return args, err
  126. }
  127. type parsedOptSpecs struct {
  128. opts []*getopt.OptionSpec
  129. desc map[*getopt.OptionSpec]string
  130. argDesc map[*getopt.OptionSpec]string
  131. argGenerator map[*getopt.OptionSpec]eval.Callable
  132. }
  133. func parseGetoptOptSpecs(v any) (parsedOptSpecs, error) {
  134. result := parsedOptSpecs{
  135. nil, map[*getopt.OptionSpec]string{},
  136. map[*getopt.OptionSpec]string{}, map[*getopt.OptionSpec]eval.Callable{}}
  137. var err error
  138. errIterate := vals.Iterate(v, func(v any) bool {
  139. m, ok := v.(vals.Map)
  140. if !ok {
  141. err = fmt.Errorf("opt should be map, got %s", vals.Kind(v))
  142. return false
  143. }
  144. opt := &getopt.OptionSpec{}
  145. getStringField := func(k string) (string, bool, error) {
  146. v, ok := m.Index(k)
  147. if !ok {
  148. return "", false, nil
  149. }
  150. if vs, ok := v.(string); ok {
  151. return vs, true, nil
  152. }
  153. return "", false,
  154. fmt.Errorf("%s should be string, got %s", k, vals.Kind(v))
  155. }
  156. getCallableField := func(k string) (eval.Callable, bool, error) {
  157. v, ok := m.Index(k)
  158. if !ok {
  159. return nil, false, nil
  160. }
  161. if vb, ok := v.(eval.Callable); ok {
  162. return vb, true, nil
  163. }
  164. return nil, false,
  165. fmt.Errorf("%s should be fn, got %s", k, vals.Kind(v))
  166. }
  167. getBoolField := func(k string) (bool, bool, error) {
  168. v, ok := m.Index(k)
  169. if !ok {
  170. return false, false, nil
  171. }
  172. if vb, ok := v.(bool); ok {
  173. return vb, true, nil
  174. }
  175. return false, false,
  176. fmt.Errorf("%s should be bool, got %s", k, vals.Kind(v))
  177. }
  178. if s, ok, errGet := getStringField("short"); ok {
  179. r, size := utf8.DecodeRuneInString(s)
  180. if r == utf8.RuneError || size != len(s) {
  181. err = fmt.Errorf(
  182. "short should be exactly one rune, got %v", parse.Quote(s))
  183. return false
  184. }
  185. opt.Short = r
  186. } else if errGet != nil {
  187. err = errGet
  188. return false
  189. }
  190. if s, ok, errGet := getStringField("long"); ok {
  191. opt.Long = s
  192. } else if errGet != nil {
  193. err = errGet
  194. return false
  195. }
  196. if opt.Short == 0 && opt.Long == "" {
  197. err = errors.New(
  198. "opt should have at least one of short and long forms")
  199. return false
  200. }
  201. argRequired, _, errGet := getBoolField("arg-required")
  202. if errGet != nil {
  203. err = errGet
  204. return false
  205. }
  206. argOptional, _, errGet := getBoolField("arg-optional")
  207. if errGet != nil {
  208. err = errGet
  209. return false
  210. }
  211. switch {
  212. case argRequired && argOptional:
  213. err = errors.New(
  214. "opt cannot have both arg-required and arg-optional")
  215. return false
  216. case argRequired:
  217. opt.Arity = getopt.RequiredArgument
  218. case argOptional:
  219. opt.Arity = getopt.OptionalArgument
  220. }
  221. if s, ok, errGet := getStringField("desc"); ok {
  222. result.desc[opt] = s
  223. } else if errGet != nil {
  224. err = errGet
  225. return false
  226. }
  227. if s, ok, errGet := getStringField("arg-desc"); ok {
  228. result.argDesc[opt] = s
  229. } else if errGet != nil {
  230. err = errGet
  231. return false
  232. }
  233. if f, ok, errGet := getCallableField("completer"); ok {
  234. result.argGenerator[opt] = f
  235. } else if errGet != nil {
  236. err = errGet
  237. return false
  238. }
  239. result.opts = append(result.opts, opt)
  240. return true
  241. })
  242. if errIterate != nil {
  243. err = errIterate
  244. }
  245. return result, err
  246. }
  247. func parseGetoptArgHandlers(v any) ([]eval.Callable, bool, error) {
  248. var argHandlers []eval.Callable
  249. var variadic bool
  250. var err error
  251. errIterate := vals.Iterate(v, func(v any) bool {
  252. sv, ok := v.(string)
  253. if ok {
  254. if sv == "..." {
  255. variadic = true
  256. return true
  257. }
  258. err = fmt.Errorf(
  259. "string except for ... not allowed as argument handler, got %s",
  260. parse.Quote(sv))
  261. return false
  262. }
  263. argHandler, ok := v.(eval.Callable)
  264. if !ok {
  265. err = fmt.Errorf(
  266. "argument handler should be fn, got %s", vals.Kind(v))
  267. }
  268. argHandlers = append(argHandlers, argHandler)
  269. return true
  270. })
  271. if errIterate != nil {
  272. err = errIterate
  273. }
  274. return argHandlers, variadic, err
  275. }