pkg.re/essentialkaos/ek.v11@v12.41.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) 2022 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  }