Skip to content

Commit 981c548

Browse files
authored
Merge pull request #385 from Pycord-Development/autocomplete
Merge autocomplete into master
2 parents 416f97c + fd02cf1 commit 981c548

File tree

3 files changed

+59
-20
lines changed

3 files changed

+59
-20
lines changed

discord/commands/commands.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from ..member import Member
3737
from ..user import User
3838
from ..message import Message
39-
from .context import ApplicationContext
39+
from .context import ApplicationContext, AutocompleteContext
4040
from ..utils import find, get_or_fetch, async_all
4141
from ..errors import ValidationError, ClientException
4242
from .errors import ApplicationCommandError, CheckFailure, ApplicationCommandInvokeError
@@ -492,15 +492,22 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
492492
await self.callback(ctx, **kwargs)
493493

494494
async def invoke_autocomplete_callback(self, interaction: Interaction):
495+
values = { i.name: i.default for i in self.options }
496+
495497
for op in interaction.data.get("options", []):
496498
if op.get("focused", False):
497499
option = find(lambda o: o.name == op["name"], self.options)
498-
result = await option.autocomplete(interaction, op.get("value", None))
500+
values.update({
501+
i["name"]:i["value"]
502+
for i in interaction.data["options"]
503+
})
504+
ctx = AutocompleteContext(interaction, command=self, focused=option, value=op.get("value"), options=values)
505+
result = await option.autocomplete(ctx)
499506
choices = [
500507
o if isinstance(o, OptionChoice) else OptionChoice(o)
501508
for o in result
502509
]
503-
await interaction.response.send_autocomplete_result(choices=choices)
510+
return await interaction.response.send_autocomplete_result(choices=choices)
504511

505512
def qualified_name(self):
506513
return self.name

discord/commands/context.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import discord
3333
from discord.state import ConnectionState
3434

35-
from .commands import ApplicationCommand
35+
from .commands import ApplicationCommand, Option
3636
from ..cog import Cog
3737

3838
from ..guild import Guild
@@ -142,3 +142,34 @@ def cog(self) -> Optional[Cog]:
142142
return None
143143

144144
return self.command.cog
145+
146+
147+
class AutocompleteContext:
148+
"""Represents context for a slash command's option autocomplete.
149+
150+
This class is not created manually and is instead passed to an Option's autocomplete callback.
151+
152+
.. versionadded:: 2.0
153+
154+
Attributes
155+
-----------
156+
interaction: :class:`.Interaction`
157+
The interaction object that invoked the autocomplete.
158+
command: :class:`.ApplicationCommand`
159+
The command that this context belongs to.
160+
focused: :class:`.Option`
161+
The option the user is currently typing.
162+
value: :class:`.str`
163+
The content of the focused option.
164+
options :class:`.dict`
165+
A name to value mapping of the options that the user has selected before this option.
166+
"""
167+
168+
__slots__ = ("interaction", "command", "focused", "value", "options")
169+
170+
def __init__(self, interaction: Interaction, *, command: ApplicationCommand, focused: Option, value: str, options: dict) -> None:
171+
self.interaction = interaction
172+
self.command = command
173+
self.focused = focused
174+
self.value = value
175+
self.options = options

discord/utils.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,19 @@
7474

7575

7676
__all__ = (
77-
"oauth_url",
78-
"snowflake_time",
79-
"time_snowflake",
80-
"find",
81-
"get",
82-
"sleep_until",
83-
"utcnow",
84-
"remove_markdown",
85-
"escape_markdown",
86-
"escape_mentions",
87-
"as_chunks",
88-
"format_dt",
77+
'oauth_url',
78+
'snowflake_time',
79+
'time_snowflake',
80+
'find',
81+
'get',
82+
'sleep_until',
83+
'utcnow',
84+
'remove_markdown',
85+
'escape_markdown',
86+
'escape_mentions',
87+
'as_chunks',
88+
'format_dt',
89+
'basic_autocomplete',
8990
"generate_snowflake",
9091
)
9192

@@ -130,6 +131,7 @@ def __get__(self, instance, owner):
130131
from .abc import Snowflake
131132
from .invite import Invite
132133
from .template import Template
134+
from .commands.context import AutocompleteContext
133135
from .interactions import Interaction
134136

135137
class _RequestLike(Protocol):
@@ -1034,7 +1036,7 @@ def format_dt(dt: datetime.datetime, /, style: Optional[TimestampStyle] = None)
10341036
return f'<t:{int(dt.timestamp())}>'
10351037
return f'<t:{int(dt.timestamp())}:{style}>'
10361038

1037-
1039+
10381040
def generate_snowflake(dt: Optional[datetime.datetime] = None) -> int:
10391041
"""Returns a numeric snowflake pretending to be created at the given date but more accurate and random than time_snowflake.
10401042
If dt is not passed, it makes one from the current time using utcnow.
@@ -1092,14 +1094,13 @@ async def autocomplete(interaction):
10921094
Callable[[:class:`Interaction`, :class:`str`], Coroutine[List[:class:`str`]]]
10931095
A wrapped callback for the autocomplete.
10941096
"""
1095-
async def autocomplete_callback(interaction: Interaction,
1096-
value: str) -> List[str]:
1097+
async def autocomplete_callback(ctx: AutocompleteContext) -> List[str]:
10971098
_values = values # since we reassign later, python considers it local if we don't do this
10981099

10991100
if callable(_values):
11001101
_values = _values(interaction)
11011102
if asyncio.iscoroutine(_values):
11021103
_values = await _values
1103-
return ([x for x in _values if x.lower().startswith(value.lower())])[:25]
1104+
return ([x for x in _values if x.lower().startswith(ctx.value.lower())])[:25]
11041105

11051106
return autocomplete_callback

0 commit comments

Comments
 (0)