aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2019-03-12 05:37:14 -0400
committerRapptz <[email protected]>2019-03-12 05:37:34 -0400
commit8a153bfaad377ada032cc7818abc68790efbdad2 (patch)
tree7d26b77e9d78b84d9d1b4f0204a674ced4101276
parent[commands] Separate view parsing errors from BadArgument. (diff)
downloaddiscord.py-8a153bfaad377ada032cc7818abc68790efbdad2.tar.xz
discord.py-8a153bfaad377ada032cc7818abc68790efbdad2.zip
[commands] Refactor quoted_word free function to a StringView method.
Technically a breaking change, however this interface was not documented or guaranteed to exist.
-rw-r--r--discord/ext/commands/core.py7
-rw-r--r--discord/ext/commands/view.py166
2 files changed, 85 insertions, 88 deletions
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
index e652467b..85bb1b9f 100644
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -33,7 +33,6 @@ import discord
from .errors import *
from .cooldowns import Cooldown, BucketType, CooldownMapping
-from .view import quoted_word
from . import converter as converters
from ._types import _BaseCommand
from .cog import Cog
@@ -421,7 +420,7 @@ class Command(_BaseCommand):
if consume_rest_is_special:
argument = view.read_rest().strip()
else:
- argument = quoted_word(view)
+ argument = view.get_quoted_word()
view.previous = previous
return await self.do_conversion(ctx, converter, argument, param)
@@ -434,7 +433,7 @@ class Command(_BaseCommand):
previous = view.index
view.skip_ws()
- argument = quoted_word(view)
+ argument = view.get_quoted_word()
try:
value = await self.do_conversion(ctx, converter, argument, param)
except CommandError:
@@ -450,7 +449,7 @@ class Command(_BaseCommand):
async def _transform_greedy_var_pos(self, ctx, param, converter):
view = ctx.view
previous = view.index
- argument = quoted_word(view)
+ argument = view.get_quoted_word()
try:
value = await self.do_conversion(ctx, converter, argument, param)
except CommandError:
diff --git a/discord/ext/commands/view.py b/discord/ext/commands/view.py
index ad34e0a4..91cc06b2 100644
--- a/discord/ext/commands/view.py
+++ b/discord/ext/commands/view.py
@@ -26,6 +26,28 @@ DEALINGS IN THE SOFTWARE.
from .errors import UnexpectedQuoteError, InvalidEndOfQuotedStringError, ExpectedClosingQuoteError
+# map from opening quotes to closing quotes
+_quotes = {
+ '"': '"',
+ "‘": "’",
+ "‚": "‛",
+ "“": "”",
+ "„": "‟",
+ "⹂": "⹂",
+ "「": "」",
+ "『": "』",
+ "〝": "〞",
+ "﹁": "﹂",
+ "﹃": "﹄",
+ """: """,
+ "「": "」",
+ "«": "»",
+ "‹": "›",
+ "《": "》",
+ "〈": "〉",
+}
+_all_quotes = set(_quotes.keys()) | set(_quotes.values())
+
class StringView:
def __init__(self, buffer):
self.index = 0
@@ -104,93 +126,69 @@ class StringView:
self.index += pos
return result
- def __repr__(self):
- return '<StringView pos: {0.index} prev: {0.previous} end: {0.end} eof: {0.eof}>'.format(self)
+ def get_quoted_word(self):
+ current = self.current
+ if current is None:
+ return None
-# Parser
+ close_quote = _quotes.get(current)
+ is_quoted = bool(close_quote)
+ if is_quoted:
+ result = []
+ _escaped_quotes = (current, close_quote)
+ else:
+ result = [current]
+ _escaped_quotes = _all_quotes
-# map from opening quotes to closing quotes
-_quotes = {
- '"': '"',
- "‘": "’",
- "‚": "‛",
- "“": "”",
- "„": "‟",
- "⹂": "⹂",
- "「": "」",
- "『": "』",
- "〝": "〞",
- "﹁": "﹂",
- "﹃": "﹄",
- """: """,
- "「": "」",
- "«": "»",
- "‹": "›",
- "《": "》",
- "〈": "〉",
-}
-_all_quotes = set(_quotes.keys()) | set(_quotes.values())
-
-def quoted_word(view):
- current = view.current
-
- if current is None:
- return None
-
- close_quote = _quotes.get(current)
- is_quoted = bool(close_quote)
- if is_quoted:
- result = []
- _escaped_quotes = (current, close_quote)
- else:
- result = [current]
- _escaped_quotes = _all_quotes
-
- while not view.eof:
- current = view.get()
- if not current:
- if is_quoted:
- # unexpected EOF
- raise ExpectedClosingQuoteError(close_quote)
- return ''.join(result)
-
- # currently we accept strings in the format of "hello world"
- # to embed a quote inside the string you must escape it: "a \"world\""
- if current == '\\':
- next_char = view.get()
- if not next_char:
- # string ends with \ and no character after it
+ while not self.eof:
+ current = self.get()
+ if not current:
if is_quoted:
- # if we're quoted then we're expecting a closing quote
+ # unexpected EOF
raise ExpectedClosingQuoteError(close_quote)
- # if we aren't then we just let it through
return ''.join(result)
- if next_char in _escaped_quotes:
- # escaped quote
- result.append(next_char)
- else:
- # different escape character, ignore it
- view.undo()
- result.append(current)
- continue
-
- if not is_quoted and current in _all_quotes:
- # we aren't quoted
- raise UnexpectedQuoteError(current)
-
- # closing quote
- if is_quoted and current == close_quote:
- next_char = view.get()
- valid_eof = not next_char or next_char.isspace()
- if not valid_eof:
- raise InvalidEndOfQuotedStringError(next_char)
-
- # we're quoted so it's okay
- return ''.join(result)
-
- if current.isspace() and not is_quoted:
- # end of word found
- return ''.join(result)
-
- result.append(current)
+ # currently we accept strings in the format of "hello world"
+ # to embed a quote inside the string you must escape it: "a \"world\""
+ if current == '\\':
+ next_char = self.get()
+ if not next_char:
+ # string ends with \ and no character after it
+ if is_quoted:
+ # if we're quoted then we're expecting a closing quote
+ raise ExpectedClosingQuoteError(close_quote)
+ # if we aren't then we just let it through
+ return ''.join(result)
+
+ if next_char in _escaped_quotes:
+ # escaped quote
+ result.append(next_char)
+ else:
+ # different escape character, ignore it
+ self.undo()
+ result.append(current)
+ continue
+
+ if not is_quoted and current in _all_quotes:
+ # we aren't quoted
+ raise UnexpectedQuoteError(current)
+
+ # closing quote
+ if is_quoted and current == close_quote:
+ next_char = self.get()
+ valid_eof = not next_char or next_char.isspace()
+ if not valid_eof:
+ raise InvalidEndOfQuotedStringError(next_char)
+
+ # we're quoted so it's okay
+ return ''.join(result)
+
+ if current.isspace() and not is_quoted:
+ # end of word found
+ return ''.join(result)
+
+ result.append(current)
+
+
+ def __repr__(self):
+ return '<StringView pos: {0.index} prev: {0.previous} end: {0.end} eof: {0.eof}>'.format(self)