@@ -211,8 +211,7 @@ class Filters:
211211 @staticmethod
212212 def command (
213213 commands : str or list ,
214- prefix : str or list = "/" ,
215- separator : str = " " ,
214+ prefixes : str or list = "/" ,
216215 case_sensitive : bool = False
217216 ):
218217 """Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
@@ -224,40 +223,63 @@ def command(
224223 a command arrives, the command itself and its arguments will be stored in the *command*
225224 field of the :obj:`Message`.
226225
227- prefix (``str`` | ``list``, *optional*):
226+ prefixes (``str`` | ``list``, *optional*):
228227 A prefix or a list of prefixes as string the filter should look for.
229- Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."].
230- Can be None or "" (empty string) to allow commands with no prefix at all.
231-
232- separator (``str``, *optional*):
233- The command arguments separator. Defaults to " " (white space).
234- Examples: /start first second, /start-first-second, /start.first.second.
228+ Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."], list(".:!").
229+ Pass None or "" (empty string) to allow commands with no prefix at all.
235230
236231 case_sensitive (``bool``, *optional*):
237232 Pass True if you want your command(s) to be case sensitive. Defaults to False.
238233 Examples: when True, command="Start" would trigger /Start but not /start.
239234 """
235+ command_re = re .compile (r"([\"'])(.*?)(?<!\\)\1|(\S+)" )
240236
241237 def func (flt , message ):
242238 text = message .text or message .caption
243239 message .command = None
244240
245- if text :
246- for p in flt .p :
247- if text .startswith (p ):
248- s = text .split (flt .s )
249- c , a = s [0 ][len (p ):], s [1 :]
250- c = c if flt .cs else c .lower ()
251- message .command = ([c ] + a ) if c in flt .c else None
252- break
241+ if not text :
242+ return False
243+
244+ pattern = r"^{}(?:\s|$)" if flt .case_sensitive else r"(?i)^{}(?:\s|$)"
245+
246+ for prefix in flt .prefixes :
247+ if not text .startswith (prefix ):
248+ continue
249+
250+ without_prefix = text [len (prefix ):]
251+
252+ for cmd in flt .commands :
253+ if not re .match (pattern .format (re .escape (cmd )), without_prefix ):
254+ continue
255+
256+ # match.groups are 1-indexed, group(1) is the quote, group(2) is the text
257+ # between the quotes, group(3) is unquoted, whitespace-split text
258+
259+ # Remove the escape character from the arguments
260+ message .command = [cmd ] + [
261+ re .sub (r"\\([\"'])" , r"\1" , m .group (2 ) or m .group (3 ) or "" )
262+ for m in command_re .finditer (without_prefix [len (cmd ):])
263+ ]
264+
265+ return True
253266
254- return bool ( message . command )
267+ return False
255268
256269 commands = commands if type (commands ) is list else [commands ]
257270 commands = {c if case_sensitive else c .lower () for c in commands }
258- prefixes = set (prefix ) if prefix else {"" }
259271
260- return create (func , "CommandFilter" , c = commands , p = prefixes , s = separator , cs = case_sensitive )
272+ prefixes = [] if prefixes is None else prefixes
273+ prefixes = prefixes if type (prefixes ) is list else [prefixes ]
274+ prefixes = set (prefixes ) if prefixes else {"" }
275+
276+ return create (
277+ func ,
278+ "CommandFilter" ,
279+ commands = commands ,
280+ prefixes = prefixes ,
281+ case_sensitive = case_sensitive
282+ )
261283
262284 @staticmethod
263285 def regex (pattern , flags : int = 0 ):
0 commit comments