aboutsummaryrefslogtreecommitdiff
path: root/lib/util.cpp
diff options
context:
space:
mode:
authorHubert Chathi <uhoreg@debian.org>2019-06-25 16:33:24 -0400
committerHubert Chathi <uhoreg@debian.org>2019-06-25 16:33:24 -0400
commit72d5660efd0755bb53a8699cd39865155400d288 (patch)
treeed7e7537e6a3eb7e8b92226c4015f9bfc8e11c5a /lib/util.cpp
parent52407a933bfe1fcc5f3aa1dccaa0b9a8279aa634 (diff)
parent681203f951d13e9e8eaf772435cac28c6d74cd42 (diff)
downloadlibquotient-72d5660efd0755bb53a8699cd39865155400d288.tar.gz
libquotient-72d5660efd0755bb53a8699cd39865155400d288.zip
Merge branch 'upstream' (v0.5.2)
Diffstat (limited to 'lib/util.cpp')
-rw-r--r--lib/util.cpp110
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