Skip to content

Commit

Permalink
Remove magic from autocomplete (#312)
Browse files Browse the repository at this point in the history
  • Loading branch information
GnomedDev committed Nov 13, 2024
1 parent 556ef6b commit cb75eda
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 101 deletions.
35 changes: 14 additions & 21 deletions examples/feature_showcase/autocomplete.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use futures::{Stream, StreamExt};
use std::fmt::Write as _;

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

async fn autocomplete_name<'a>(
_ctx: Context<'_>,
partial: &'a str,
) -> impl Stream<Item = String> + 'a {
futures::stream::iter(&["Amanda", "Bob", "Christian", "Danny", "Ester", "Falk"])
.filter(move |name| futures::future::ready(name.starts_with(partial)))
.map(|name| name.to_string())
) -> serenity::CreateAutocompleteResponse {
let choices = ["Amanda", "Bob", "Christian", "Danny", "Ester", "Falk"]
.into_iter()
.filter(move |name| name.starts_with(partial))
.map(serenity::AutocompleteChoice::from)
.collect();

serenity::CreateAutocompleteResponse::new().set_choices(choices)
}

async fn autocomplete_number(
_ctx: Context<'_>,
_partial: &str,
) -> impl Iterator<Item = serenity::AutocompleteChoice> {
) -> serenity::CreateAutocompleteResponse {
// Dummy choices
[1_u32, 2, 3, 4, 5].iter().map(|&n| {
let choices = [1_u32, 2, 3, 4, 5].iter().map(|&n| {
serenity::AutocompleteChoice::new(
format!("{n} (why did discord even give autocomplete choices separate labels)"),
n,
)
})
});

serenity::CreateAutocompleteResponse::new().set_choices(choices.collect())
}

/// Greet a user. Showcasing autocomplete!
Expand Down
4 changes: 2 additions & 2 deletions examples/invocation_data/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ async fn my_check(ctx: Context<'_>) -> Result<bool, Error> {
Ok(true)
}

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

std::iter::empty()
serenity::CreateAutocompleteResponse::new()
}

/// Test command to ensure that invocation_data works
Expand Down
17 changes: 1 addition & 16 deletions macros/src/command/slash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,7 @@ pub fn generate_parameters(inv: &Invocation) -> Result<Vec<proc_macro2::TokenStr
quote::quote! { Some(|
ctx: poise::ApplicationContext<'_, _, _>,
partial: &str,
| Box::pin(async move {
use ::poise::futures_util::{Stream, StreamExt};

let choices_stream = ::poise::into_stream!(
#autocomplete_fn(ctx.into(), partial).await
);
let choices_vec = choices_stream
.take(25)
// T or AutocompleteChoice<T> -> AutocompleteChoice<T>
.map(poise::serenity_prelude::AutocompleteChoice::from)
.collect()
.await;

let mut response = poise::serenity_prelude::CreateAutocompleteResponse::default();
Ok(response.set_choices(choices_vec))
})) }
| Box::pin(#autocomplete_fn(ctx.into(), partial))) }
}
None => quote::quote! { None },
};
Expand Down
18 changes: 11 additions & 7 deletions src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,17 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
pub async fn autocomplete_command<'a, U, E>(
ctx: crate::Context<'a, U, E>,
partial: &'a str,
) -> impl Iterator<Item = String> + 'a {
ctx.framework()
.options()
.commands
.iter()
.filter(move |cmd| cmd.name.starts_with(partial))
.map(|cmd| cmd.name.to_string())
) -> serenity::CreateAutocompleteResponse {
let commands = ctx.framework().options.commands.iter();
let filtered_commands = commands
.filter(|cmd| cmd.name.starts_with(partial))
.take(25);

let choices = filtered_commands
.map(|cmd| serenity::AutocompleteChoice::from(&cmd.name))
.collect();

serenity::CreateAutocompleteResponse::new().set_choices(choices)
}

/// Lists servers of which the bot is a member of, including their member counts, sorted
Expand Down
8 changes: 1 addition & 7 deletions src/dispatch/slash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,7 @@ async fn run_autocomplete<U, E>(
use ::serenity::json::*; // as_str() access via trait for simd-json

// Generate an autocomplete response
let autocomplete_response = match autocomplete_callback(ctx, partial_input).await {
Ok(x) => x,
Err(e) => {
tracing::warn!("couldn't generate autocomplete response: {e}");
return Ok(());
}
};
let autocomplete_response = autocomplete_callback(ctx, partial_input).await;

// Send the generates autocomplete response
if let Err(e) = ctx
Expand Down
41 changes: 0 additions & 41 deletions src/slash_argument/into_stream.rs

This file was deleted.

3 changes: 0 additions & 3 deletions src/slash_argument/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,3 @@ pub use slash_trait::*;

mod context_menu;
pub use context_menu::*;

mod into_stream;
pub use into_stream::*;
5 changes: 1 addition & 4 deletions src/structs/slash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,7 @@ pub struct CommandParameter<U, E> {
for<'a> fn(
crate::ApplicationContext<'a, U, E>,
&'a str,
) -> BoxFuture<
'a,
Result<serenity::CreateAutocompleteResponse, crate::SlashArgError>,
>,
) -> BoxFuture<'a, serenity::CreateAutocompleteResponse>,
>,
#[doc(hidden)]
pub __non_exhaustive: (),
Expand Down

0 comments on commit cb75eda

Please sign in to comment.