Migrate Remaining Chat Settings Commands to Helix API (#4040)
This commit is contained in:
@@ -8,6 +8,110 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
namespace _helpers_internal {
|
||||
|
||||
int skipSpace(const QStringRef &view, int startPos)
|
||||
{
|
||||
while (startPos < view.length() && view.at(startPos).isSpace())
|
||||
{
|
||||
startPos++;
|
||||
}
|
||||
return startPos - 1;
|
||||
}
|
||||
|
||||
bool matchesIgnorePlural(const QStringRef &word, const QString &singular)
|
||||
{
|
||||
if (!word.startsWith(singular))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (word.length() == singular.length())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return word.length() == singular.length() + 1 &&
|
||||
word.at(word.length() - 1).toLatin1() == 's';
|
||||
}
|
||||
|
||||
std::pair<uint64_t, bool> findUnitMultiplierToSec(const QStringRef &view,
|
||||
int &pos)
|
||||
{
|
||||
// Step 1. find end of unit
|
||||
int startIdx = pos;
|
||||
int endIdx = view.length();
|
||||
for (; pos < view.length(); pos++)
|
||||
{
|
||||
auto c = view.at(pos);
|
||||
if (c.isSpace() || c.isDigit())
|
||||
{
|
||||
endIdx = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pos--;
|
||||
|
||||
// TODO(QT6): use sliced (more readable)
|
||||
auto unit = view.mid(startIdx, endIdx - startIdx);
|
||||
if (unit.isEmpty())
|
||||
{
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
|
||||
auto first = unit.at(0).toLatin1();
|
||||
switch (first)
|
||||
{
|
||||
case 's': {
|
||||
if (unit.length() == 1 ||
|
||||
matchesIgnorePlural(unit, QStringLiteral("second")))
|
||||
{
|
||||
return std::make_pair(1, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'm': {
|
||||
if (unit.length() == 1 ||
|
||||
matchesIgnorePlural(unit, QStringLiteral("minute")))
|
||||
{
|
||||
return std::make_pair(60, true);
|
||||
}
|
||||
if ((unit.length() == 2 && unit.at(1).toLatin1() == 'o') ||
|
||||
matchesIgnorePlural(unit, QStringLiteral("month")))
|
||||
{
|
||||
return std::make_pair(60 * 60 * 24 * 30, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'h': {
|
||||
if (unit.length() == 1 ||
|
||||
matchesIgnorePlural(unit, QStringLiteral("hour")))
|
||||
{
|
||||
return std::make_pair(60 * 60, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'd': {
|
||||
if (unit.length() == 1 ||
|
||||
matchesIgnorePlural(unit, QStringLiteral("day")))
|
||||
{
|
||||
return std::make_pair(60 * 60 * 24, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'w': {
|
||||
if (unit.length() == 1 ||
|
||||
matchesIgnorePlural(unit, QStringLiteral("week")))
|
||||
{
|
||||
return std::make_pair(60 * 60 * 24 * 7, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
|
||||
} // namespace _helpers_internal
|
||||
using namespace _helpers_internal;
|
||||
|
||||
bool startsWithOrContains(const QString &str1, const QString &str2,
|
||||
Qt::CaseSensitivity caseSensitivity, bool startsWith)
|
||||
{
|
||||
@@ -93,4 +197,76 @@ QString formatUserMention(const QString &userName, bool isFirstWord,
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t parseDurationToSeconds(const QString &inputString,
|
||||
uint64_t noUnitMultiplier)
|
||||
{
|
||||
if (inputString.length() == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO(QT6): use QStringView
|
||||
QStringRef input(&inputString);
|
||||
input = input.trimmed();
|
||||
|
||||
uint64_t currentValue = 0;
|
||||
|
||||
bool visitingNumber = true; // input must start with a number
|
||||
int numberStartIdx = 0;
|
||||
|
||||
for (int pos = 0; pos < input.length(); pos++)
|
||||
{
|
||||
QChar c = input.at(pos);
|
||||
|
||||
if (visitingNumber && !c.isDigit())
|
||||
{
|
||||
uint64_t parsed =
|
||||
(uint64_t)input.mid(numberStartIdx, pos - numberStartIdx)
|
||||
.toUInt();
|
||||
|
||||
if (c.isSpace())
|
||||
{
|
||||
pos = skipSpace(input, pos) + 1;
|
||||
if (pos >= input.length())
|
||||
{
|
||||
// input like "40 ", this shouldn't happen
|
||||
// since we trimmed the view
|
||||
return -1;
|
||||
}
|
||||
c = input.at(pos);
|
||||
}
|
||||
|
||||
auto result = findUnitMultiplierToSec(input, pos);
|
||||
if (!result.second)
|
||||
{
|
||||
return -1; // invalid unit or leading spaces (shouldn't happen)
|
||||
}
|
||||
|
||||
currentValue += parsed * result.first;
|
||||
visitingNumber = false;
|
||||
}
|
||||
else if (!visitingNumber && !c.isSpace())
|
||||
{
|
||||
if (!c.isDigit())
|
||||
{
|
||||
return -1; // expected a digit
|
||||
}
|
||||
visitingNumber = true;
|
||||
numberStartIdx = pos;
|
||||
}
|
||||
// else: visitingNumber && isDigit || !visitingNumber && isSpace
|
||||
}
|
||||
|
||||
if (visitingNumber)
|
||||
{
|
||||
if (numberStartIdx != 0)
|
||||
{
|
||||
return -1; // input like "1w 3s 70", 70 what? apples?
|
||||
}
|
||||
currentValue += input.toUInt() * noUnitMultiplier;
|
||||
}
|
||||
|
||||
return (int64_t)currentValue;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -2,11 +2,54 @@
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QStringRef>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// only qualified for tests
|
||||
namespace _helpers_internal {
|
||||
|
||||
/**
|
||||
* Skips all spaces.
|
||||
* The caller must guarantee view.at(startPos).isSpace().
|
||||
*
|
||||
* @param view The string to skip spaces in.
|
||||
* @param startPos The starting position (there must be a space in the view).
|
||||
* @return The position of the last space.
|
||||
*/
|
||||
int skipSpace(const QStringRef &view, int startPos);
|
||||
|
||||
/**
|
||||
* Checks if `word` equals `expected` (singular) or `expected` + 's' (plural).
|
||||
*
|
||||
* @param word Word to test. Must not be empty.
|
||||
* @param expected Singular of the expected word.
|
||||
* @return true if `word` is singular or plural of `expected`.
|
||||
*/
|
||||
bool matchesIgnorePlural(const QStringRef &word, const QString &expected);
|
||||
|
||||
/**
|
||||
* Tries to find the unit starting at `pos` and returns its multiplier so
|
||||
* `valueInUnit * multiplier = valueInSeconds` (e.g. 60 for minutes).
|
||||
*
|
||||
* Supported units are
|
||||
* 'w[eek(s)]', 'd[ay(s)]',
|
||||
* 'h[our(s)]', 'm[inute(s)]', 's[econd(s)]'.
|
||||
* The unit must be in lowercase.
|
||||
*
|
||||
* @param view A view into a string
|
||||
* @param pos The starting position.
|
||||
* This is set to the last position of the unit
|
||||
* if it's a valid unit, undefined otherwise.
|
||||
* @return (multiplier, ok)
|
||||
*/
|
||||
std::pair<uint64_t, bool> findUnitMultiplierToSec(const QStringRef &view,
|
||||
int &pos);
|
||||
|
||||
} // namespace _helpers_internal
|
||||
|
||||
/**
|
||||
* @brief startsWithOrContains is a wrapper for checking
|
||||
* whether str1 starts with or contains str2 within itself
|
||||
@@ -29,6 +72,37 @@ QString kFormatNumbers(const int &number);
|
||||
|
||||
QColor getRandomColor(const QString &userId);
|
||||
|
||||
/**
|
||||
* Parses a duration.
|
||||
* Spaces are allowed before and after a unit but not mandatory.
|
||||
* Supported units are
|
||||
* 'w[eek(s)]', 'd[ay(s)]',
|
||||
* 'h[our(s)]', 'm[inute(s)]', 's[econd(s)]'.
|
||||
* Units must be lowercase.
|
||||
*
|
||||
* If the entire input string is a number (e.g. "12345"),
|
||||
* then it's multiplied by noUnitMultiplier.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - "1w 2h"
|
||||
* - "1w 1w 0s 4d" (2weeks, 4days)
|
||||
* - "5s3h4w" (4weeks, 3hours, 5seconds)
|
||||
* - "30m"
|
||||
* - "1 week"
|
||||
* - "5 days 12 hours"
|
||||
* - "10" (10 * noUnitMultiplier seconds)
|
||||
*
|
||||
* @param inputString A non-empty string to parse
|
||||
* @param noUnitMultiplier A multiplier if the input string only contains one number.
|
||||
* For example, if a number without a unit should be interpreted
|
||||
* as a minute, set this to 60. If it should be interpreted
|
||||
* as a second, set it to 1 (default).
|
||||
* @return The parsed duration in seconds, -1 if the input is invalid.
|
||||
*/
|
||||
int64_t parseDurationToSeconds(const QString &inputString,
|
||||
uint64_t noUnitMultiplier = 1);
|
||||
|
||||
/**
|
||||
* @brief Takes a user's name and some formatting parameter and spits out the standardized way to format it
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user