summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp4
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp76
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/data/links.md25
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp1
4 files changed, 104 insertions, 2 deletions
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp
index b6a275f59c..7e18a10895 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -399,8 +399,10 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det)
MD_SPAN_A_DETAIL *detail = static_cast<MD_SPAN_A_DETAIL *>(det);
QString url = QString::fromUtf8(detail->href.text, int(detail->href.size));
QString title = QString::fromUtf8(detail->title.text, int(detail->title.size));
+ charFmt.setAnchor(true);
charFmt.setAnchorHref(url);
- charFmt.setAnchorNames(QStringList(title));
+ if (!title.isEmpty())
+ charFmt.setToolTip(title);
charFmt.setForeground(m_palette.link());
qCDebug(lcMD) << "anchor" << url << title;
} break;
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index c9a63920c3..7bd321becc 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -56,10 +56,13 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcMDW, "qt.text.markdown.writer")
static const QChar Space = QLatin1Char(' ');
+static const QChar Tab = QLatin1Char('\t');
static const QChar Newline = QLatin1Char('\n');
+static const QChar CarriageReturn = QLatin1Char('\r');
static const QChar LineBreak = QChar(0x2028);
static const QChar DoubleQuote = QLatin1Char('"');
static const QChar Backtick = QLatin1Char('`');
+static const QChar Backslash = QLatin1Char('\\');
static const QChar Period = QLatin1Char('.');
QTextMarkdownWriter::QTextMarkdownWriter(QTextStream &stream, QTextDocument::MarkdownFeatures features)
@@ -291,6 +294,72 @@ static void maybeEscapeFirstChar(QString &s)
}
}
+struct LineEndPositions {
+ const QChar *lineEnd;
+ const QChar *nextLineBegin;
+};
+
+static LineEndPositions findLineEnd(const QChar *begin, const QChar *end)
+{
+ LineEndPositions result{ end, end };
+
+ while (begin < end) {
+ if (*begin == Newline) {
+ result.lineEnd = begin;
+ result.nextLineBegin = begin + 1;
+ break;
+ } else if (*begin == CarriageReturn) {
+ result.lineEnd = begin;
+ result.nextLineBegin = begin + 1;
+ if (((begin + 1) < end) && begin[1] == Newline)
+ ++result.nextLineBegin;
+ break;
+ }
+
+ ++begin;
+ }
+
+ return result;
+}
+
+static bool isBlankLine(const QChar *begin, const QChar *end)
+{
+ while (begin < end) {
+ if (*begin != Space && *begin != Tab)
+ return false;
+ ++begin;
+ }
+ return true;
+}
+
+static QString createLinkTitle(const QString &title)
+{
+ QString result;
+ result.reserve(title.size() + 2);
+ result += DoubleQuote;
+
+ const QChar *data = title.data();
+ const QChar *end = data + title.size();
+
+ while (data < end) {
+ const auto lineEndPositions = findLineEnd(data, end);
+
+ if (!isBlankLine(data, lineEndPositions.lineEnd)) {
+ while (data < lineEndPositions.nextLineBegin) {
+ if (*data == DoubleQuote)
+ result += Backslash;
+ result += *data;
+ ++data;
+ }
+ }
+
+ data = lineEndPositions.nextLineBegin;
+ }
+
+ result += DoubleQuote;
+ return result;
+}
+
int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ignoreFormat, bool ignoreEmpty)
{
if (block.text().isEmpty() && ignoreEmpty)
@@ -445,7 +514,12 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
col += s.length();
} else if (fmt.hasProperty(QTextFormat::AnchorHref)) {
QString s = QLatin1Char('[') + fragmentText + QLatin1String("](") +
- fmt.property(QTextFormat::AnchorHref).toString() + QLatin1Char(')');
+ fmt.property(QTextFormat::AnchorHref).toString();
+ if (fmt.hasProperty(QTextFormat::TextToolTip)) {
+ s += Space;
+ s += createLinkTitle(fmt.property(QTextFormat::TextToolTip).toString());
+ }
+ s += QLatin1Char(')');
if (wrap && col + s.length() > ColumnLimit) {
m_stream << Newline << wrapIndentString;
col = m_wrappedLineIndent;
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/links.md b/tests/auto/gui/text/qtextmarkdownwriter/data/links.md
new file mode 100644
index 0000000000..33cdb2b3ab
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/data/links.md
@@ -0,0 +1,25 @@
+A series of links.
+
+[link](/uri)
+
+[link]()
+
+[link](/uri "title")
+
+[link](/uri "àbcdè")
+
+[link](/uri "title title \" title title")
+
+[link](/url "title \"&quot;")
+
+[link](/url "title
+title
+title title
+\"title\" title \"
+title")
+
+* [link](/url "title")
+* [link](/url)
+* [link](/url "title
+title title")
+* nonlink
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
index d15e856a20..31592c7f0f 100644
--- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
+++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
@@ -368,6 +368,7 @@ void tst_QTextMarkdownWriter::rewriteDocument_data()
QTest::newRow("example") << "example.md";
QTest::newRow("list items after headings") << "headingsAndLists.md";
QTest::newRow("word wrap") << "wordWrap.md";
+ QTest::newRow("links") << "links.md";
}
void tst_QTextMarkdownWriter::rewriteDocument()