Skip to content

Improve simultaneous choices and autocomplete handling#342

Draft
KubaZ2 wants to merge 5 commits intoalphafrom
improve/simultaneous-choices-and-autocomplete-handling
Draft

Improve simultaneous choices and autocomplete handling#342
KubaZ2 wants to merge 5 commits intoalphafrom
improve/simultaneous-choices-and-autocomplete-handling

Conversation

@KubaZ2
Copy link
Copy Markdown
Member

@KubaZ2 KubaZ2 commented May 7, 2026

Fixes #341

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

The documentation preview is available at https://preview.netcord.dev/342.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses issue #341 where an explicitly configured autocomplete provider on an enum slash-command parameter was never invoked because enum parameters defaulted to a built-in choices provider. The update adjusts parameter/provider resolution to ensure autocomplete can be used for enums and enforces the Discord constraint that choices and autocomplete cannot be enabled simultaneously.

Changes:

  • Refactors SlashCommandParameter initialization to prioritize explicitly specified AutocompleteProviderType over default enum choices handling.
  • Adds a guard that throws when both a choices provider and an autocomplete provider are specified for the same parameter.
  • Adds a test/repro module demonstrating enum autocomplete usage.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
Tests/NetCord.Test/ApplicationCommands/Commands.cs Adds a repro command/module with an enum parameter using AutocompleteProviderType.
NetCord.Services/ApplicationCommands/SlashCommandParameter.cs Refactors provider-selection logic to avoid “choices + autocomplete” conflicts and to allow enum autocomplete.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread NetCord.Services/ApplicationCommands/SlashCommandParameter.cs
Comment thread Tests/NetCord.Test/ApplicationCommands/Commands.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment on lines +68 to +89
if (slashCommandParameterAttribute?.ChoicesProviderType is { } choicesProviderType)
{
var slashCommandParameterAttribute = (SlashCommandParameterAttribute)slashCommandParameterAttributes[0];
(TypeReader, NonNullableType, DefaultValue) = ParametersHelper.GetParameterInfo<TContext, ISlashCommandTypeReader, SlashCommandTypeReader<TContext>>(type, parameter, slashCommandParameterAttribute.TypeReaderType, configuration.TypeReaders, configuration.EnumTypeReader);

var name = Name = slashCommandParameterAttribute.Name ?? configuration.ParameterNameProcessor.ProcessParameterName(parameter.Name!, configuration);
Description = slashCommandParameterAttribute.Description ?? string.Format(configuration.DefaultParameterDescriptionFormat, name);

LocalizationPath = path.Add(new SlashCommandParameterLocalizationPathSegment(name));

var choicesProviderType = slashCommandParameterAttribute.ChoicesProviderType;
if (choicesProviderType is null)
ChoicesProvider = TypeReader.ChoicesProvider;
else
{
if (!choicesProviderType.IsAssignableTo(typeof(IChoicesProvider<TContext>)))
throw new InvalidOperationException($"'{choicesProviderType}' is not assignable to '{nameof(IChoicesProvider<>)}<{typeof(TContext).Name}>'.");
ChoicesProvider = (IChoicesProvider<TContext>)Activator.CreateInstance(choicesProviderType)!;
}

AutocompleteProviderType = slashCommandParameterAttribute.AutocompleteProviderType ?? TypeReader.AutocompleteProviderType;
AllowedChannelTypes = slashCommandParameterAttribute.AllowedChannelTypes ?? TypeReader.AllowedChannelTypes;
MaxValue = slashCommandParameterAttribute._maxValue ?? TypeReader.GetMaxValue(this, configuration);
MinValue = slashCommandParameterAttribute._minValue ?? TypeReader.GetMinValue(this, configuration);
MaxLength = slashCommandParameterAttribute._maxLength ?? TypeReader.GetMaxLength(this, configuration);
MinLength = slashCommandParameterAttribute._minLength ?? TypeReader.GetMinLength(this, configuration);
if (slashCommandParameterAttribute.AutocompleteProviderType is not null)
ThrowBothProvidersSpecifiedException(method);

if (!typeof(IChoicesProvider<TContext>).IsAssignableFrom(choicesProviderType))
throw new InvalidDefinitionException($"'{choicesProviderType}' is not assignable to '{typeof(IChoicesProvider<TContext>)}'.", method);

ChoicesProvider = (IChoicesProvider<TContext>)Activator.CreateInstance(choicesProviderType)!;
}
else
else if (slashCommandParameterAttribute?.AutocompleteProviderType is { } autocompleteProviderType)
AutocompleteProviderType = autocompleteProviderType;
else if (typeReader.ChoicesProvider is { } choicesProvider)
{
(TypeReader, NonNullableType, DefaultValue) = ParametersHelper.GetParameterInfo<TContext, ISlashCommandTypeReader, SlashCommandTypeReader<TContext>>(type, parameter, null, configuration.TypeReaders, configuration.EnumTypeReader);

var name = Name = configuration.ParameterNameProcessor.ProcessParameterName(parameter.Name!, configuration);
LocalizationPath = path.Add(new SlashCommandParameterLocalizationPathSegment(name));
Description = string.Format(configuration.DefaultParameterDescriptionFormat, name);
ChoicesProvider = TypeReader.ChoicesProvider;
AutocompleteProviderType = TypeReader.AutocompleteProviderType;
AllowedChannelTypes = TypeReader.AllowedChannelTypes;
MaxValue = TypeReader.GetMaxValue(this, configuration);
MinValue = TypeReader.GetMinValue(this, configuration);
MaxLength = TypeReader.GetMaxLength(this, configuration);
MinLength = TypeReader.GetMinLength(this, configuration);
if (typeReader.AutocompleteProviderType is not null)
ThrowBothProvidersSpecifiedException(method);

ChoicesProvider = choicesProvider;
}
else
AutocompleteProviderType = typeReader.AutocompleteProviderType;

Comment thread Tests/NetCord.Test/ApplicationCommands/Commands.cs Outdated
@AraHaan
Copy link
Copy Markdown

AraHaan commented May 7, 2026

Lmk when this is ready for merge.

@AraHaan
Copy link
Copy Markdown

AraHaan commented May 7, 2026

I see that there is a new test failure now.

@KubaZ2
Copy link
Copy Markdown
Member Author

KubaZ2 commented May 7, 2026

I see that there is a new test failure now.

Yeah, I was moving code from my laptop. I need to make a big refactor to make it pass. Basically they fail because I throw InvalidOperationException instead of InvalidDefinitionException and there is no easy way to change that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When making an Autocomplete provider for an enum it never gets run at all.

3 participants