@@ -150,24 +150,6 @@ def categorize(func: Union[Callable, Iterable], category: str) -> None:
150
150
setattr (func , HELP_CATEGORY , category )
151
151
152
152
153
- def parse_quoted_string (string : str , preserve_quotes : bool ) -> List [str ]:
154
- """
155
- Parse a quoted string into a list of arguments
156
- :param string: the string being parsed
157
- :param preserve_quotes: if True, then quotes will not be stripped
158
- """
159
- if isinstance (string , list ):
160
- # arguments are already a list, return the list we were passed
161
- lexed_arglist = string
162
- else :
163
- # Use shlex to split the command line into a list of arguments based on shell rules
164
- lexed_arglist = shlex .split (string , comments = False , posix = False )
165
-
166
- if not preserve_quotes :
167
- lexed_arglist = [utils .strip_quotes (arg ) for arg in lexed_arglist ]
168
- return lexed_arglist
169
-
170
-
171
153
def with_category (category : str ) -> Callable :
172
154
"""A decorator to apply a category to a command function."""
173
155
def cat_decorator (func ):
@@ -176,10 +158,37 @@ def cat_decorator(func):
176
158
return cat_decorator
177
159
178
160
161
+ def _get_command_arg_list (to_parse : Union [str , Statement ], preserve_quotes : bool ) -> List [str ]:
162
+ """
163
+ Called by the argument_list and argparse wrappers to retrieve just the arguments being
164
+ passed to their do_* methods as a list.
165
+
166
+ :param to_parse: what is being passed to the do_* method. It can be one of two types:
167
+ 1. An already parsed Statement
168
+ 2. An argument string in cases where a do_* method is explicitly called
169
+ e.g.: Calling do_help('alias create') would cause to_parse to be 'alias create'
170
+
171
+ :param preserve_quotes: if True, then quotes will not be stripped from the arguments
172
+ :return: the arguments in a list
173
+ """
174
+ if isinstance (to_parse , Statement ):
175
+ # In the case of a Statement, we already have what we need
176
+ if preserve_quotes :
177
+ return to_parse .arg_list
178
+ else :
179
+ return to_parse .argv [1 :]
180
+ else :
181
+ # We only have the argument string. Use the parser to split this string.
182
+ parsed_arglist = StatementParser .shlex_split (to_parse )
183
+ if not preserve_quotes :
184
+ parsed_arglist = [utils .strip_quotes (arg ) for arg in parsed_arglist ]
185
+
186
+ return parsed_arglist
187
+
188
+
179
189
def with_argument_list (* args : List [Callable ], preserve_quotes : bool = False ) -> Callable [[List ], Optional [bool ]]:
180
190
"""A decorator to alter the arguments passed to a do_* cmd2 method. Default passes a string of whatever the user
181
- typed. With this decorator, the decorated method will receive a list of arguments parsed from user input using
182
- shlex.split().
191
+ typed. With this decorator, the decorated method will receive a list of arguments parsed from user input.
183
192
184
193
:param args: Single-element positional argument list containing do_* method this decorator is wrapping
185
194
:param preserve_quotes: if True, then argument quotes will not be stripped
@@ -189,9 +198,9 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) ->
189
198
190
199
def arg_decorator (func : Callable ):
191
200
@functools .wraps (func )
192
- def cmd_wrapper (self , cmdline ):
193
- lexed_arglist = parse_quoted_string ( cmdline , preserve_quotes )
194
- return func (self , lexed_arglist )
201
+ def cmd_wrapper (cmd2_instance , statement : Union [ str , Statement ] ):
202
+ parsed_arglist = _get_command_arg_list ( statement , preserve_quotes )
203
+ return func (cmd2_instance , parsed_arglist )
195
204
196
205
cmd_wrapper .__doc__ = func .__doc__
197
206
return cmd_wrapper
@@ -214,16 +223,17 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, preserve
214
223
import functools
215
224
216
225
# noinspection PyProtectedMember
217
- def arg_decorator (func : Callable [[ Statement ], Optional [ bool ]] ):
226
+ def arg_decorator (func : Callable ):
218
227
@functools .wraps (func )
219
- def cmd_wrapper (instance , cmdline ):
220
- lexed_arglist = parse_quoted_string (cmdline , preserve_quotes )
228
+ def cmd_wrapper (cmd2_instance , statement : Union [str , Statement ]):
229
+ parsed_arglist = _get_command_arg_list (statement , preserve_quotes )
230
+
221
231
try :
222
- args , unknown = argparser .parse_known_args (lexed_arglist )
232
+ args , unknown = argparser .parse_known_args (parsed_arglist )
223
233
except SystemExit :
224
234
return
225
235
else :
226
- return func (instance , args , unknown )
236
+ return func (cmd2_instance , args , unknown )
227
237
228
238
# argparser defaults the program name to sys.argv[0]
229
239
# we want it to be the name of our command
@@ -256,16 +266,18 @@ def with_argparser(argparser: argparse.ArgumentParser,
256
266
import functools
257
267
258
268
# noinspection PyProtectedMember
259
- def arg_decorator (func : Callable [[ Statement ], Optional [ bool ]] ):
269
+ def arg_decorator (func : Callable ):
260
270
@functools .wraps (func )
261
- def cmd_wrapper (instance , cmdline ):
262
- lexed_arglist = parse_quoted_string (cmdline , preserve_quotes )
271
+ def cmd_wrapper (cmd2_instance , statement : Union [str , Statement ]):
272
+
273
+ parsed_arglist = _get_command_arg_list (statement , preserve_quotes )
274
+
263
275
try :
264
- args = argparser .parse_args (lexed_arglist )
276
+ args = argparser .parse_args (parsed_arglist )
265
277
except SystemExit :
266
278
return
267
279
else :
268
- return func (instance , args )
280
+ return func (cmd2_instance , args )
269
281
270
282
# argparser defaults the program name to sys.argv[0]
271
283
# we want it to be the name of our command
@@ -742,8 +754,7 @@ def tokens_for_completion(self, line: str, begidx: int, endidx: int) -> Tuple[Li
742
754
# Parse the line into tokens
743
755
while True :
744
756
try :
745
- # Use non-POSIX parsing to keep the quotes around the tokens
746
- initial_tokens = shlex .split (tmp_line [:tmp_endidx ], comments = False , posix = False )
757
+ initial_tokens = StatementParser .shlex_split (tmp_line [:tmp_endidx ])
747
758
748
759
# If the cursor is at an empty token outside of a quoted string,
749
760
# then that is the token being completed. Add it to the list.
@@ -1735,7 +1746,7 @@ def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement])
1735
1746
# Fix those annoying problems that occur with terminal programs like "less" when you pipe to them
1736
1747
if self .stdin .isatty ():
1737
1748
import subprocess
1738
- proc = subprocess .Popen (shlex . split ( 'stty sane' ) )
1749
+ proc = subprocess .Popen ([ 'stty' , ' sane'] )
1739
1750
proc .communicate ()
1740
1751
1741
1752
try :
0 commit comments