Coverage for typer/_completion_classes.py: 100%

109 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-11-13 11:07 +0000

1import os 1habcdefg

2import re 1habcdefg

3import sys 1habcdefg

4from typing import Any, Dict, List, Tuple 1habcdefg

5 

6import click 1habcdefg

7import click.parser 1habcdefg

8import click.shell_completion 1habcdefg

9 

10from ._completion_shared import ( 1habcdefg

11 COMPLETION_SCRIPT_BASH, 

12 COMPLETION_SCRIPT_FISH, 

13 COMPLETION_SCRIPT_POWER_SHELL, 

14 COMPLETION_SCRIPT_ZSH, 

15 Shells, 

16) 

17 

18try: 1habcdefg

19 import shellingham 1habcdefg

20except ImportError: # pragma: no cover 

21 shellingham = None 

22 

23 

24class BashComplete(click.shell_completion.BashComplete): 1habcdefg

25 name = Shells.bash.value 1habcdefg

26 source_template = COMPLETION_SCRIPT_BASH 1habcdefg

27 

28 def source_vars(self) -> Dict[str, Any]: 1habcdefg

29 return { 1abcdefg

30 "complete_func": self.func_name, 

31 "autocomplete_var": self.complete_var, 

32 "prog_name": self.prog_name, 

33 } 

34 

35 def get_completion_args(self) -> Tuple[List[str], str]: 1habcdefg

36 cwords = click.parser.split_arg_string(os.environ["COMP_WORDS"]) 1habcdefg

37 cword = int(os.environ["COMP_CWORD"]) 1habcdefg

38 args = cwords[1:cword] 1habcdefg

39 

40 try: 1habcdefg

41 incomplete = cwords[cword] 1habcdefg

42 except IndexError: 1habcdefg

43 incomplete = "" 1habcdefg

44 

45 return args, incomplete 1habcdefg

46 

47 def format_completion(self, item: click.shell_completion.CompletionItem) -> str: 1habcdefg

48 # TODO: Explore replicating the new behavior from Click, with item types and 

49 # triggering completion for files and directories 

50 # return f"{item.type},{item.value}" 

51 return f"{item.value}" 1habcdefg

52 

53 def complete(self) -> str: 1habcdefg

54 args, incomplete = self.get_completion_args() 1habcdefg

55 completions = self.get_completions(args, incomplete) 1habcdefg

56 out = [self.format_completion(item) for item in completions] 1habcdefg

57 return "\n".join(out) 1habcdefg

58 

59 

60class ZshComplete(click.shell_completion.ZshComplete): 1habcdefg

61 name = Shells.zsh.value 1habcdefg

62 source_template = COMPLETION_SCRIPT_ZSH 1habcdefg

63 

64 def source_vars(self) -> Dict[str, Any]: 1habcdefg

65 return { 1abcdefg

66 "complete_func": self.func_name, 

67 "autocomplete_var": self.complete_var, 

68 "prog_name": self.prog_name, 

69 } 

70 

71 def get_completion_args(self) -> Tuple[List[str], str]: 1habcdefg

72 completion_args = os.getenv("_TYPER_COMPLETE_ARGS", "") 1habcdefg

73 cwords = click.parser.split_arg_string(completion_args) 1habcdefg

74 args = cwords[1:] 1habcdefg

75 if args and not completion_args.endswith(" "): 1habcdefg

76 incomplete = args[-1] 1habcdefg

77 args = args[:-1] 1habcdefg

78 else: 

79 incomplete = "" 1habcdefg

80 return args, incomplete 1habcdefg

81 

82 def format_completion(self, item: click.shell_completion.CompletionItem) -> str: 1habcdefg

83 def escape(s: str) -> str: 1habcdefg

84 return ( 1abcdefg

85 s.replace('"', '""') 

86 .replace("'", "''") 

87 .replace("$", "\\$") 

88 .replace("`", "\\`") 

89 .replace(":", r"\\:") 

90 ) 

91 

92 # TODO: Explore replicating the new behavior from Click, pay attention to 

93 # the difference with and without escape 

94 # return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" 

95 if item.help: 1habcdefg

96 return f'"{escape(item.value)}":"{escape(item.help)}"' 1habcdefg

97 else: 

98 return f'"{escape(item.value)}"' 1habcdefg

99 

100 def complete(self) -> str: 1habcdefg

101 args, incomplete = self.get_completion_args() 1habcdefg

102 completions = self.get_completions(args, incomplete) 1habcdefg

103 res = [self.format_completion(item) for item in completions] 1habcdefg

104 if res: 1habcdefg

105 args_str = "\n".join(res) 1habcdefg

106 return f"_arguments '*: :(({args_str}))'" 1habcdefg

107 else: 

108 return "_files" 1habcdefg

109 

110 

111class FishComplete(click.shell_completion.FishComplete): 1habcdefg

112 name = Shells.fish.value 1habcdefg

113 source_template = COMPLETION_SCRIPT_FISH 1habcdefg

114 

115 def source_vars(self) -> Dict[str, Any]: 1habcdefg

116 return { 1abcdefg

117 "complete_func": self.func_name, 

118 "autocomplete_var": self.complete_var, 

119 "prog_name": self.prog_name, 

120 } 

121 

122 def get_completion_args(self) -> Tuple[List[str], str]: 1habcdefg

123 completion_args = os.getenv("_TYPER_COMPLETE_ARGS", "") 1habcdefg

124 cwords = click.parser.split_arg_string(completion_args) 1habcdefg

125 args = cwords[1:] 1habcdefg

126 if args and not completion_args.endswith(" "): 1habcdefg

127 incomplete = args[-1] 1habcdefg

128 args = args[:-1] 1habcdefg

129 else: 

130 incomplete = "" 1habcdefg

131 return args, incomplete 1habcdefg

132 

133 def format_completion(self, item: click.shell_completion.CompletionItem) -> str: 1habcdefg

134 # TODO: Explore replicating the new behavior from Click, pay attention to 

135 # the difference with and without formatted help 

136 # if item.help: 

137 # return f"{item.type},{item.value}\t{item.help}" 

138 

139 # return f"{item.type},{item.value} 

140 if item.help: 1habcdefg

141 formatted_help = re.sub(r"\s", " ", item.help) 1habcdefg

142 return f"{item.value}\t{formatted_help}" 1habcdefg

143 else: 

144 return f"{item.value}" 1habcdefg

145 

146 def complete(self) -> str: 1habcdefg

147 complete_action = os.getenv("_TYPER_COMPLETE_FISH_ACTION", "") 1habcdefg

148 args, incomplete = self.get_completion_args() 1habcdefg

149 completions = self.get_completions(args, incomplete) 1habcdefg

150 show_args = [self.format_completion(item) for item in completions] 1habcdefg

151 if complete_action == "get-args": 1habcdefg

152 if show_args: 1habcdefg

153 return "\n".join(show_args) 1habcdefg

154 elif complete_action == "is-args": 1habcdefg

155 if show_args: 1habcdefg

156 # Activate complete args (no files) 

157 sys.exit(0) 1habcdefg

158 else: 

159 # Deactivate complete args (allow files) 

160 sys.exit(1) 1habcdefg

161 return "" # pragma: no cover 

162 

163 

164class PowerShellComplete(click.shell_completion.ShellComplete): 1habcdefg

165 name = Shells.powershell.value 1habcdefg

166 source_template = COMPLETION_SCRIPT_POWER_SHELL 1habcdefg

167 

168 def source_vars(self) -> Dict[str, Any]: 1habcdefg

169 return { 1abcdefg

170 "complete_func": self.func_name, 

171 "autocomplete_var": self.complete_var, 

172 "prog_name": self.prog_name, 

173 } 

174 

175 def get_completion_args(self) -> Tuple[List[str], str]: 1habcdefg

176 completion_args = os.getenv("_TYPER_COMPLETE_ARGS", "") 1habcdefg

177 incomplete = os.getenv("_TYPER_COMPLETE_WORD_TO_COMPLETE", "") 1habcdefg

178 cwords = click.parser.split_arg_string(completion_args) 1habcdefg

179 args = cwords[1:-1] if incomplete else cwords[1:] 1habcdefg

180 return args, incomplete 1habcdefg

181 

182 def format_completion(self, item: click.shell_completion.CompletionItem) -> str: 1habcdefg

183 return f"{item.value}:::{item.help or ' '}" 1habcdefg

184 

185 

186def completion_init() -> None: 1habcdefg

187 click.shell_completion.add_completion_class(BashComplete, Shells.bash.value) 1habcdefg

188 click.shell_completion.add_completion_class(ZshComplete, Shells.zsh.value) 1habcdefg

189 click.shell_completion.add_completion_class(FishComplete, Shells.fish.value) 1habcdefg

190 click.shell_completion.add_completion_class( 1habcdefg

191 PowerShellComplete, Shells.powershell.value 

192 ) 

193 click.shell_completion.add_completion_class(PowerShellComplete, Shells.pwsh.value) 1habcdefg