pkg.re/essentialkaos/ek@v12.36.0+incompatible/usage/completion/fish/fish.go (about) 1 // Package fish provides methods for generating fish completion 2 package fish 3 4 // ////////////////////////////////////////////////////////////////////////////////// // 5 // // 6 // Copyright (c) 2021 ESSENTIAL KAOS // 7 // Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> // 8 // // 9 // ////////////////////////////////////////////////////////////////////////////////// // 10 11 import ( 12 "fmt" 13 "strings" 14 15 "pkg.re/essentialkaos/ek.v12/fmtc" 16 "pkg.re/essentialkaos/ek.v12/usage" 17 ) 18 19 // ////////////////////////////////////////////////////////////////////////////////// // 20 21 const _FISH_TEMPLATE = `# Completion for {{COMPNAME}} 22 # This completion is automatically generated 23 24 function __fish_{{COMPNAME_SAFE}}_no_command 25 set cmd (commandline -opc) 26 if [ (count $cmd) -eq 1 ] 27 return 0 28 end 29 return 1 30 end 31 32 function __fish_{{COMPNAME_SAFE}}_using_command 33 set cmd (commandline -opc) 34 if [ (count $cmd) -gt 1 ] 35 if [ $argv[1] = $cmd[2] ] 36 return 0 37 end 38 end 39 return 1 40 end 41 42 {{GLOBAL_OPTS}} 43 {{COMMANDS}}` 44 45 // ////////////////////////////////////////////////////////////////////////////////// // 46 47 // Generate generates fish completion code 48 func Generate(info *usage.Info, name string) string { 49 result := _FISH_TEMPLATE 50 51 result = strings.Replace(result, "{{GLOBAL_OPTS}}", genGlobalOptionCompletion(info, name), -1) 52 result = strings.Replace(result, "{{COMMANDS}}", genCommandsCompletion(info, name), -1) 53 result = strings.Replace(result, "{{COMPNAME}}", name, -1) 54 55 nameSafe := strings.Replace(name, "-", "_", -1) 56 57 result = strings.Replace(result, "{{COMPNAME_SAFE}}", nameSafe, -1) 58 59 return result 60 } 61 62 // ////////////////////////////////////////////////////////////////////////////////// // 63 64 // genGlobalOptionCompletion generates completion for global options 65 func genGlobalOptionCompletion(info *usage.Info, name string) string { 66 var result string 67 68 nonGlobalOptions := make(map[string]bool) 69 70 for _, cmd := range info.Commands { 71 for _, opt := range cmd.BoundOptions { 72 nonGlobalOptions[opt] = true 73 } 74 } 75 76 for _, opt := range info.Options { 77 if nonGlobalOptions[opt.Long] { 78 continue 79 } 80 81 result += genOptionCompletion(opt, name, "") 82 } 83 84 return result 85 } 86 87 // genCommandsCompletion generates completion for all commands 88 func genCommandsCompletion(info *usage.Info, name string) string { 89 if len(info.Commands) == 0 { 90 return "" 91 } 92 93 var result string 94 95 for _, cmd := range info.Commands { 96 result += genCommandCompletion(cmd, name) 97 98 if len(cmd.BoundOptions) == 0 { 99 result += "\n" 100 continue 101 } 102 103 for _, optName := range cmd.BoundOptions { 104 opt := info.GetOption(optName) 105 106 if opt == nil { 107 result += "\n" 108 continue 109 } 110 111 result += genOptionCompletion(opt, name, cmd.Name) 112 } 113 114 result += "\n" 115 } 116 117 return result 118 } 119 120 // genOptionCompletion generates completion for option 121 func genOptionCompletion(opt *usage.Option, name, cmd string) string { 122 var result string 123 124 if cmd == "" { 125 result = "complete -f -n '__fish_{{COMPNAME_SAFE}}_no_command' " 126 } else { 127 result = fmt.Sprintf("complete -f -n '__fish_{{COMPNAME_SAFE}}_using_command %s' ", cmd) 128 } 129 130 result += fmt.Sprintf("-c %s ", name) 131 result += fmt.Sprintf("-l %s ", opt.Long) 132 133 if opt.Short != "" { 134 result += fmt.Sprintf("-s %s ", opt.Short) 135 } 136 137 result += fmt.Sprintf("-d '%s'\n", fmtc.Clean(opt.Desc)) 138 139 return result 140 } 141 142 // genCommandCompletion generates completion for command 143 func genCommandCompletion(cmd *usage.Command, name string) string { 144 result := "complete -f -n '__fish_{{COMPNAME}}_no_command' " 145 result += fmt.Sprintf("-c %s ", name) 146 result += fmt.Sprintf("-a '%s' ", cmd.Name) 147 result += fmt.Sprintf("-d '%s'\n", fmtc.Clean(cmd.Desc)) 148 149 return result 150 }