diff options
author | Hubert Chathi <uhoreg@debian.org> | 2019-06-25 16:33:24 -0400 |
---|---|---|
committer | Hubert Chathi <uhoreg@debian.org> | 2019-06-25 16:33:24 -0400 |
commit | 72d5660efd0755bb53a8699cd39865155400d288 (patch) | |
tree | ed7e7537e6a3eb7e8b92226c4015f9bfc8e11c5a /lib/util.cpp | |
parent | 52407a933bfe1fcc5f3aa1dccaa0b9a8279aa634 (diff) | |
parent | 681203f951d13e9e8eaf772435cac28c6d74cd42 (diff) | |
download | libquotient-72d5660efd0755bb53a8699cd39865155400d288.tar.gz libquotient-72d5660efd0755bb53a8699cd39865155400d288.zip |
Merge branch 'upstream' (v0.5.2)
Diffstat (limited to 'lib/util.cpp')
-rw-r--r-- | lib/util.cpp | 110 |
1 files changed, 106 insertions, 4 deletions
diff --git a/lib/util.cpp b/lib/util.cpp index 1773fcfe..17674b84 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -19,6 +19,9 @@ #include "util.h" #include <QtCore/QRegularExpression> +#include <QtCore/QStandardPaths> +#include <QtCore/QDir> +#include <QtCore/QStringBuilder> static const auto RegExpOptions = QRegularExpression::CaseInsensitiveOption @@ -35,29 +38,128 @@ static void linkifyUrls(QString& htmlEscapedText) // comma or dot // Note: outer parentheses are a part of C++ raw string delimiters, not of // the regex (see http://en.cppreference.com/w/cpp/language/string_literal). + // Note2: the next-outer parentheses are \N in the replacement. static const QRegularExpression FullUrlRegExp(QStringLiteral( - R"(((www\.(?!\.)|[a-z][a-z0-9+.-]*://)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))" + R"(\b((www\.(?!\.)(?!(\w|\.|-)+@)|(https?|ftp|magnet)://)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))" ), RegExpOptions); // email address: // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars] static const QRegularExpression EmailAddressRegExp(QStringLiteral( - R"((mailto:)?(\b(\w|\.|-)+@(\w|\.|-)+\.\w+\b))" + R"(\b(mailto:)?((\w|\.|-)+@(\w|\.|-)+\.\w+\b))" + ), RegExpOptions); + // An interim liberal implementation of + // https://matrix.org/docs/spec/appendices.html#identifier-grammar + static const QRegularExpression MxIdRegExp(QStringLiteral( + R"((^|[^<>/])([!#@][-a-z0-9_=/.]{1,252}:[-.a-z0-9]+))" ), RegExpOptions); - // NOTE: htmlEscapedText is already HTML-escaped! No literal <,>,& + // NOTE: htmlEscapedText is already HTML-escaped! No literal <,>,&," htmlEscapedText.replace(EmailAddressRegExp, QStringLiteral(R"(<a href="mailto:\2">\1\2</a>)")); htmlEscapedText.replace(FullUrlRegExp, QStringLiteral(R"(<a href="\1">\1</a>)")); + htmlEscapedText.replace(MxIdRegExp, + QStringLiteral(R"(\1<a href="https://matrix.to/#/\2">\2</a>)")); +} + +QString QMatrixClient::sanitized(const QString& plainText) +{ + auto text = plainText; + text.remove(QChar(0x202e)); + text.remove(QChar(0x202d)); + return text; } QString QMatrixClient::prettyPrint(const QString& plainText) { auto pt = QStringLiteral("<span style='white-space:pre-wrap'>") + - plainText.toHtmlEscaped() + QStringLiteral("</span>"); + plainText.toHtmlEscaped() + QStringLiteral("</span>"); pt.replace('\n', QStringLiteral("<br/>")); linkifyUrls(pt); return pt; } + +QString QMatrixClient::cacheLocation(const QString& dirName) +{ + const QString cachePath = + QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + % '/' % dirName % '/'; + QDir dir; + if (!dir.exists(cachePath)) + dir.mkpath(cachePath); + return cachePath; +} + +// Tests for function_traits<> + +#ifdef Q_CC_CLANG +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCSimplifyInspection" +#endif +using namespace QMatrixClient; + +int f(); +static_assert(std::is_same<fn_return_t<decltype(f)>, int>::value, + "Test fn_return_t<>"); + +void f1(int); +static_assert(function_traits<decltype(f1)>::arg_number == 1, + "Test fn_arg_number"); + +void f2(int, QString); +static_assert(std::is_same<fn_arg_t<decltype(f2), 1>, QString>::value, + "Test fn_arg_t<>"); + +struct S { int mf(); }; +static_assert(is_callable_v<decltype(&S::mf)>, "Test member function"); +static_assert(returns<int, decltype(&S::mf)>(), "Test returns<> with member function"); + +struct Fo { int operator()(); }; +static_assert(is_callable_v<Fo>, "Test is_callable<> with function object"); +static_assert(function_traits<Fo>::arg_number == 0, "Test function object"); +static_assert(std::is_same<fn_return_t<Fo>, int>::value, + "Test return type of function object"); + +struct Fo1 { void operator()(int); }; +static_assert(function_traits<Fo1>::arg_number == 1, "Test function object 1"); +static_assert(is_callable_v<Fo1>, "Test is_callable<> with function object 1"); +static_assert(std::is_same<fn_arg_t<Fo1>, int>(), + "Test fn_arg_t defaulting to first argument"); + +#if (!defined(_MSC_VER) || _MSC_VER >= 1910) +static auto l = [] { return 1; }; +static_assert(is_callable_v<decltype(l)>, "Test is_callable_v<> with lambda"); +static_assert(std::is_same<fn_return_t<decltype(l)>, int>::value, + "Test fn_return_t<> with lambda"); +#endif + +template <typename T> +struct fn_object +{ + static int smf(double) { return 0; } +}; +template <> +struct fn_object<QString> +{ + void operator()(QString); +}; +static_assert(is_callable_v<fn_object<QString>>, "Test function object"); +static_assert(returns<void, fn_object<QString>>(), + "Test returns<> with function object"); +static_assert(!is_callable_v<fn_object<int>>, "Test non-function object"); +// FIXME: These two don't work +//static_assert(is_callable_v<decltype(&fn_object<int>::smf)>, +// "Test static member function"); +//static_assert(returns<int, decltype(&fn_object<int>::smf)>(), +// "Test returns<> with static member function"); + +template <typename T> +QString ft(T&&) { return {}; } +static_assert(std::is_same<fn_arg_t<decltype(ft<QString>)>, QString&&>(), + "Test function templates"); + +#ifdef Q_CC_CLANG +#pragma clang diagnostic pop +#endif |