[commands] Added handling for unicode quotes
This commit is contained in:
parent
871a262ee3
commit
ea061ef9b2
@ -108,13 +108,42 @@ class StringView:
|
|||||||
|
|
||||||
# Parser
|
# Parser
|
||||||
|
|
||||||
|
# map from opening quotes to closing quotes
|
||||||
|
_quotes = {
|
||||||
|
'"': '"',
|
||||||
|
"'": "'",
|
||||||
|
"«": "»",
|
||||||
|
"‘": "’",
|
||||||
|
"‚": "‛",
|
||||||
|
"“": "”",
|
||||||
|
"„": "‟",
|
||||||
|
"‹": "›",
|
||||||
|
"⹂": "⹂",
|
||||||
|
"「": "」",
|
||||||
|
"『": "』",
|
||||||
|
"〝": "〞",
|
||||||
|
"﹁": "﹂",
|
||||||
|
"﹃": "﹄",
|
||||||
|
""": """,
|
||||||
|
"'": "'",
|
||||||
|
"「": "」",
|
||||||
|
"«": "»",
|
||||||
|
"‹": "›",
|
||||||
|
"《": "》",
|
||||||
|
"〈": "〉",
|
||||||
|
}
|
||||||
|
_all_quotes = set(_quotes.keys()) | set(_quotes.values())
|
||||||
|
|
||||||
def quoted_word(view):
|
def quoted_word(view):
|
||||||
current = view.current
|
current = view.current
|
||||||
|
|
||||||
if current is None:
|
if current is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
is_quoted = current == '"'
|
close_quote = _quotes.get(current)
|
||||||
|
is_quoted = bool(close_quote)
|
||||||
|
if is_quoted:
|
||||||
|
open_quote = current
|
||||||
result = [] if is_quoted else [current]
|
result = [] if is_quoted else [current]
|
||||||
|
|
||||||
while not view.eof:
|
while not view.eof:
|
||||||
@ -122,7 +151,7 @@ def quoted_word(view):
|
|||||||
if not current:
|
if not current:
|
||||||
if is_quoted:
|
if is_quoted:
|
||||||
# unexpected EOF
|
# unexpected EOF
|
||||||
raise BadArgument('Expected closing "')
|
raise BadArgument('Expected closing {}.'.format(close_quote))
|
||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
|
|
||||||
# currently we accept strings in the format of "hello world"
|
# currently we accept strings in the format of "hello world"
|
||||||
@ -133,32 +162,32 @@ def quoted_word(view):
|
|||||||
# string ends with \ and no character after it
|
# string ends with \ and no character after it
|
||||||
if is_quoted:
|
if is_quoted:
|
||||||
# if we're quoted then we're expecting a closing quote
|
# if we're quoted then we're expecting a closing quote
|
||||||
raise BadArgument('Expected closing "')
|
raise BadArgument('Expected closing {}.'.format(close_quote))
|
||||||
# if we aren't then we just let it through
|
# if we aren't then we just let it through
|
||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
|
|
||||||
if next_char == '"':
|
if next_char in ((open_quote, close_quote) if is_quoted else _all_quotes):
|
||||||
# escaped quote
|
# escaped quote
|
||||||
result.append('"')
|
result.append(next_char)
|
||||||
else:
|
else:
|
||||||
# different escape character, ignore it
|
# different escape character, ignore it
|
||||||
view.undo()
|
view.undo()
|
||||||
result.append(current)
|
result.append(current)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if not is_quoted and current in _all_quotes:
|
||||||
|
# we aren't quoted
|
||||||
|
raise BadArgument('Unexpected quote mark in non-quoted string')
|
||||||
|
|
||||||
# closing quote
|
# closing quote
|
||||||
if current == '"':
|
if is_quoted and current == close_quote:
|
||||||
next_char = view.get()
|
next_char = view.get()
|
||||||
valid_eof = not next_char or next_char.isspace()
|
valid_eof = not next_char or next_char.isspace()
|
||||||
if is_quoted:
|
if not valid_eof:
|
||||||
if not valid_eof:
|
raise BadArgument('Expected space after closing quotation')
|
||||||
raise BadArgument('Expected space after closing quotation')
|
|
||||||
|
|
||||||
# we're quoted so it's okay
|
# we're quoted so it's okay
|
||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
else:
|
|
||||||
# we aren't quoted
|
|
||||||
raise BadArgument('Unexpected quote mark in non-quoted string')
|
|
||||||
|
|
||||||
if current.isspace() and not is_quoted:
|
if current.isspace() and not is_quoted:
|
||||||
# end of word found
|
# end of word found
|
||||||
|
Loading…
x
Reference in New Issue
Block a user