fix: don't autocomplete commands mid-sentence (#6273)
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
- Minor: Made nicknames searchable in the Settings dialog search bar. (#5886)
|
- Minor: Made nicknames searchable in the Settings dialog search bar. (#5886)
|
||||||
- Minor: Added hotkey Action for opening account selector. (#6192)
|
- Minor: Added hotkey Action for opening account selector. (#6192)
|
||||||
- Minor: Add a setting to change the emote and badge thumbnail size. (#6126)
|
- Minor: Add a setting to change the emote and badge thumbnail size. (#6126)
|
||||||
|
- Bugfix: Commands are no longer tab-completable in the middle of messages. (#6273)
|
||||||
- Bugfix: Automatic streamer mode detection now works from Flatpak. (#6250)
|
- Bugfix: Automatic streamer mode detection now works from Flatpak. (#6250)
|
||||||
- Bugfix: Don't create native messaging manifest file if browser directory doesn't exist. (#6116)
|
- Bugfix: Don't create native messaging manifest file if browser directory doesn't exist. (#6116)
|
||||||
- Bugfix: Fixed scrolling now working on inputs in the settings. (#6128)
|
- Bugfix: Fixed scrolling now working on inputs in the settings. (#6128)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void TabCompletionModel::updateResults(const QString &query,
|
|||||||
const QString &fullTextContent,
|
const QString &fullTextContent,
|
||||||
int cursorPosition, bool isFirstWord)
|
int cursorPosition, bool isFirstWord)
|
||||||
{
|
{
|
||||||
this->updateSourceFromQuery(query);
|
this->updateSourceFromQuery(query, isFirstWord);
|
||||||
|
|
||||||
if (this->source_)
|
if (this->source_)
|
||||||
{
|
{
|
||||||
@@ -56,9 +56,10 @@ void TabCompletionModel::updateResults(const QString &query,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabCompletionModel::updateSourceFromQuery(const QString &query)
|
void TabCompletionModel::updateSourceFromQuery(const QString &query,
|
||||||
|
bool isFirstWord)
|
||||||
{
|
{
|
||||||
auto deducedKind = this->deduceSourceKind(query);
|
auto deducedKind = this->deduceSourceKind(query, isFirstWord);
|
||||||
if (!deducedKind)
|
if (!deducedKind)
|
||||||
{
|
{
|
||||||
// unable to determine what kind of completion is occurring
|
// unable to determine what kind of completion is occurring
|
||||||
@@ -71,7 +72,8 @@ void TabCompletionModel::updateSourceFromQuery(const QString &query)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<TabCompletionModel::SourceKind>
|
std::optional<TabCompletionModel::SourceKind>
|
||||||
TabCompletionModel::deduceSourceKind(const QString &query) const
|
TabCompletionModel::deduceSourceKind(const QString &query,
|
||||||
|
bool isFirstWord) const
|
||||||
{
|
{
|
||||||
if (query.length() < 2 || !this->channel_.isTwitchChannel())
|
if (query.length() < 2 || !this->channel_.isTwitchChannel())
|
||||||
{
|
{
|
||||||
@@ -88,7 +90,7 @@ std::optional<TabCompletionModel::SourceKind>
|
|||||||
{
|
{
|
||||||
return SourceKind::Emote;
|
return SourceKind::Emote;
|
||||||
}
|
}
|
||||||
else if (query.startsWith('/') || query.startsWith('.'))
|
else if (isFirstWord && (query.startsWith('/') || query.startsWith('.')))
|
||||||
{
|
{
|
||||||
return SourceKind::Command;
|
return SourceKind::Command;
|
||||||
}
|
}
|
||||||
@@ -97,14 +99,27 @@ std::optional<TabCompletionModel::SourceKind>
|
|||||||
// Therefore, we must also consider that the user could be completing an emote
|
// Therefore, we must also consider that the user could be completing an emote
|
||||||
// OR a mention depending on their completion settings.
|
// OR a mention depending on their completion settings.
|
||||||
|
|
||||||
if (getSettings()->userCompletionOnlyWithAt)
|
if (isFirstWord)
|
||||||
{
|
{
|
||||||
// All kinds but user are possible
|
if (getSettings()->userCompletionOnlyWithAt)
|
||||||
return SourceKind::EmoteCommand;
|
{
|
||||||
|
// All kinds but user are possible
|
||||||
|
return SourceKind::EmoteCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any kind is possible
|
||||||
|
return SourceKind::EmoteUserCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any kind is possible
|
// We don't allow for mid-message command completions,
|
||||||
return SourceKind::EmoteUserCommand;
|
// which means only emote or user tab completions are possible.
|
||||||
|
|
||||||
|
if (getSettings()->userCompletionOnlyWithAt)
|
||||||
|
{
|
||||||
|
return SourceKind::Emote;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SourceKind::EmoteUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<completion::Source> TabCompletionModel::buildSource(
|
std::unique_ptr<completion::Source> TabCompletionModel::buildSource(
|
||||||
@@ -121,6 +136,14 @@ std::unique_ptr<completion::Source> TabCompletionModel::buildSource(
|
|||||||
case SourceKind::Command: {
|
case SourceKind::Command: {
|
||||||
return this->buildCommandSource();
|
return this->buildCommandSource();
|
||||||
}
|
}
|
||||||
|
case SourceKind::EmoteUser: {
|
||||||
|
std::vector<std::unique_ptr<completion::Source>> sources;
|
||||||
|
sources.push_back(this->buildEmoteSource());
|
||||||
|
sources.push_back(this->buildUserSource(false));
|
||||||
|
|
||||||
|
return std::make_unique<completion::UnifiedSource>(
|
||||||
|
std::move(sources));
|
||||||
|
}
|
||||||
case SourceKind::EmoteCommand: {
|
case SourceKind::EmoteCommand: {
|
||||||
std::vector<std::unique_ptr<completion::Source>> sources;
|
std::vector<std::unique_ptr<completion::Source>> sources;
|
||||||
sources.push_back(this->buildEmoteSource());
|
sources.push_back(this->buildEmoteSource());
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ private:
|
|||||||
User,
|
User,
|
||||||
// Known to be a command, i.e. started with / or .
|
// Known to be a command, i.e. started with / or .
|
||||||
Command,
|
Command,
|
||||||
|
// Emote or user without : or @ .
|
||||||
|
EmoteUser,
|
||||||
// Emote or command without : or / .
|
// Emote or command without : or / .
|
||||||
EmoteCommand,
|
EmoteCommand,
|
||||||
// Emote, user, or command without :, @, / .
|
// Emote, user, or command without :, @, / .
|
||||||
@@ -51,14 +53,17 @@ private:
|
|||||||
/// The completion source will only change if the deduced completion kind
|
/// The completion source will only change if the deduced completion kind
|
||||||
/// changes (see deduceSourceKind).
|
/// changes (see deduceSourceKind).
|
||||||
/// @param query Completion query
|
/// @param query Completion query
|
||||||
void updateSourceFromQuery(const QString &query);
|
/// @param isFirstWord Whether the completion is the first word in the input
|
||||||
|
void updateSourceFromQuery(const QString &query, bool isFirstWord);
|
||||||
|
|
||||||
/// @brief Attempts to deduce the source kind from the current query. If the
|
/// @brief Attempts to deduce the source kind from the current query. If the
|
||||||
/// bound Channel is not a TwitchChannel or if the query is too short, no
|
/// bound Channel is not a TwitchChannel or if the query is too short, no
|
||||||
/// query type will be deduced to prevent completions.
|
/// query type will be deduced to prevent completions.
|
||||||
/// @param query Completion query
|
/// @param query Completion query
|
||||||
|
/// @param isFirstWord Whether the completion is the first word in the input
|
||||||
/// @return An optional SourceKind deduced from the query
|
/// @return An optional SourceKind deduced from the query
|
||||||
std::optional<SourceKind> deduceSourceKind(const QString &query) const;
|
std::optional<SourceKind> deduceSourceKind(const QString &query,
|
||||||
|
bool isFirstWord) const;
|
||||||
|
|
||||||
std::unique_ptr<completion::Source> buildSource(SourceKind kind) const;
|
std::unique_ptr<completion::Source> buildSource(SourceKind kind) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user