Skip to content

Commit cb75eda

Browse files
committed
Remove magic from autocomplete (#312)
1 parent 556ef6b commit cb75eda

File tree

8 files changed

+30
-101
lines changed

8 files changed

+30
-101
lines changed

examples/feature_showcase/autocomplete.rs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use futures::{Stream, StreamExt};
21
use std::fmt::Write as _;
32

43
use poise::serenity_prelude as serenity;
@@ -11,40 +10,34 @@ use crate::{Context, Error};
1110
// The first parameter of that function is ApplicationContext or Context, and the second parameter
1211
// is a &str of the partial input which the user has typed so far.
1312
//
14-
// As the return value of autocomplete functions, you can return a Stream, an Iterator, or an
15-
// IntoIterator like Vec<T> and [T; N].
16-
//
17-
// The returned collection type must be a &str/String (or number, if you're implementing
18-
// autocomplete on a number type). Wrap the type in serenity::AutocompleteChoice to set a custom label
19-
// for each choice which will be displayed in the Discord UI.
20-
//
21-
// Example function return types (assuming non-number parameter -> autocomplete choices are string):
22-
// - `-> impl Stream<String>`
23-
// - `-> Vec<String>`
24-
// - `-> impl Iterator<String>`
25-
// - `-> impl Iterator<&str>`
26-
// - `-> impl Iterator<serenity::AutocompleteChoice>
13+
// As the return value of autocomplete functions, you must return `serenity::CreateAutocompleteResponse`.
2714

2815
async fn autocomplete_name<'a>(
2916
_ctx: Context<'_>,
3017
partial: &'a str,
31-
) -> impl Stream<Item = String> + 'a {
32-
futures::stream::iter(&["Amanda", "Bob", "Christian", "Danny", "Ester", "Falk"])
33-
.filter(move |name| futures::future::ready(name.starts_with(partial)))
34-
.map(|name| name.to_string())
18+
) -> serenity::CreateAutocompleteResponse {
19+
let choices = ["Amanda", "Bob", "Christian", "Danny", "Ester", "Falk"]
20+
.into_iter()
21+
.filter(move |name| name.starts_with(partial))
22+
.map(serenity::AutocompleteChoice::from)
23+
.collect();
24+
25+
serenity::CreateAutocompleteResponse::new().set_choices(choices)
3526
}
3627

3728
async fn autocomplete_number(
3829
_ctx: Context<'_>,
3930
_partial: &str,
40-
) -> impl Iterator<Item = serenity::AutocompleteChoice> {
31+
) -> serenity::CreateAutocompleteResponse {
4132
// Dummy choices
42-
[1_u32, 2, 3, 4, 5].iter().map(|&n| {
33+
let choices = [1_u32, 2, 3, 4, 5].iter().map(|&n| {
4334
serenity::AutocompleteChoice::new(
4435
format!("{n} (why did discord even give autocomplete choices separate labels)"),
4536
n,
4637
)
47-
})
38+
});
39+
40+
serenity::CreateAutocompleteResponse::new().set_choices(choices.collect())
4841
}
4942

5043
/// Greet a user. Showcasing autocomplete!

examples/invocation_data/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ async fn my_check(ctx: Context<'_>) -> Result<bool, Error> {
1818
Ok(true)
1919
}
2020

21-
async fn my_autocomplete(ctx: Context<'_>, _: &str) -> impl Iterator<Item = String> {
21+
async fn my_autocomplete(ctx: Context<'_>, _: &str) -> serenity::CreateAutocompleteResponse {
2222
println!(
2323
"In autocomplete: {:?}",
2424
ctx.invocation_data::<&str>().await.as_deref()
2525
);
2626

27-
std::iter::empty()
27+
serenity::CreateAutocompleteResponse::new()
2828
}
2929

3030
/// Test command to ensure that invocation_data works

macros/src/command/slash.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,7 @@ pub fn generate_parameters(inv: &Invocation) -> Result<Vec<proc_macro2::TokenStr
3535
quote::quote! { Some(|
3636
ctx: poise::ApplicationContext<'_, _, _>,
3737
partial: &str,
38-
| Box::pin(async move {
39-
use ::poise::futures_util::{Stream, StreamExt};
40-
41-
let choices_stream = ::poise::into_stream!(
42-
#autocomplete_fn(ctx.into(), partial).await
43-
);
44-
let choices_vec = choices_stream
45-
.take(25)
46-
// T or AutocompleteChoice<T> -> AutocompleteChoice<T>
47-
.map(poise::serenity_prelude::AutocompleteChoice::from)
48-
.collect()
49-
.await;
50-
51-
let mut response = poise::serenity_prelude::CreateAutocompleteResponse::default();
52-
Ok(response.set_choices(choices_vec))
53-
})) }
38+
| Box::pin(#autocomplete_fn(ctx.into(), partial))) }
5439
}
5540
None => quote::quote! { None },
5641
};

src/builtins/mod.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,17 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
230230
pub async fn autocomplete_command<'a, U, E>(
231231
ctx: crate::Context<'a, U, E>,
232232
partial: &'a str,
233-
) -> impl Iterator<Item = String> + 'a {
234-
ctx.framework()
235-
.options()
236-
.commands
237-
.iter()
238-
.filter(move |cmd| cmd.name.starts_with(partial))
239-
.map(|cmd| cmd.name.to_string())
233+
) -> serenity::CreateAutocompleteResponse {
234+
let commands = ctx.framework().options.commands.iter();
235+
let filtered_commands = commands
236+
.filter(|cmd| cmd.name.starts_with(partial))
237+
.take(25);
238+
239+
let choices = filtered_commands
240+
.map(|cmd| serenity::AutocompleteChoice::from(&cmd.name))
241+
.collect();
242+
243+
serenity::CreateAutocompleteResponse::new().set_choices(choices)
240244
}
241245

242246
/// Lists servers of which the bot is a member of, including their member counts, sorted

src/dispatch/slash.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,7 @@ async fn run_autocomplete<U, E>(
227227
use ::serenity::json::*; // as_str() access via trait for simd-json
228228

229229
// Generate an autocomplete response
230-
let autocomplete_response = match autocomplete_callback(ctx, partial_input).await {
231-
Ok(x) => x,
232-
Err(e) => {
233-
tracing::warn!("couldn't generate autocomplete response: {e}");
234-
return Ok(());
235-
}
236-
};
230+
let autocomplete_response = autocomplete_callback(ctx, partial_input).await;
237231

238232
// Send the generates autocomplete response
239233
if let Err(e) = ctx

src/slash_argument/into_stream.rs

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/slash_argument/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,3 @@ pub use slash_trait::*;
88

99
mod context_menu;
1010
pub use context_menu::*;
11-
12-
mod into_stream;
13-
pub use into_stream::*;

src/structs/slash.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,7 @@ pub struct CommandParameter<U, E> {
157157
for<'a> fn(
158158
crate::ApplicationContext<'a, U, E>,
159159
&'a str,
160-
) -> BoxFuture<
161-
'a,
162-
Result<serenity::CreateAutocompleteResponse, crate::SlashArgError>,
163-
>,
160+
) -> BoxFuture<'a, serenity::CreateAutocompleteResponse>,
164161
>,
165162
#[doc(hidden)]
166163
pub __non_exhaustive: (),

0 commit comments

Comments
 (0)