From 8dde6b0a67ecf11fa2ddacbc139b07e5b74d4708 Mon Sep 17 00:00:00 2001 From: Mathias Hasselmann Date: Fri, 5 Jan 2024 00:06:28 +0100 Subject: [PATCH] Markdown: Follow local anchor links in text editor Github and others turn `[^footnote]` into anchor links to the next occurrence of `[^footnote]: Description`. Task-number: QTCREATORBUG-30119 Change-Id: Ieebcad8ef58ccd8c7faa6aa83a165ce3f7ea1a01 Reviewed-by: David Schulz --- src/plugins/texteditor/markdowneditor.cpp | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index a027427ef65..ca8088d3264 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -568,8 +568,13 @@ void MarkdownEditorWidget::findLinkAt(const QTextCursor &cursor, bool /*resolveTarget*/, bool /*inNextSplit*/) { - static const QStringView CAPTURE_GROUP_LINK = u"link"; - static const QRegularExpression markdownLink{R"(\[[^[\]]*\]\((?.+?)\))"}; + static const QStringView CAPTURE_GROUP_LINK = u"link"; + static const QStringView CAPTURE_GROUP_ANCHOR = u"anchor"; + + static const QRegularExpression markdownLink{ + R"(\[[^[\]]*\]\((?.+?)\))" + R"(|(?\[\^[^\]]+\])(?:[^:]|$))" + }; QTC_ASSERT(markdownLink.isValid(), return); @@ -604,6 +609,25 @@ void MarkdownEditorWidget::findLinkAt(const QTextCursor &cursor, result.linkTextEnd = match.capturedEnd() + blockOffset; processLinkCallback(result); break; + } else if (const QStringView anchor = match.capturedView(CAPTURE_GROUP_ANCHOR); + !anchor.isEmpty()) { + // Process local anchor links of the form `[^footnote]` that point + // to anchors in the current document: `[^footnote]: Description`. + + const QTextCursor target = cursor.document()->find(anchor + u':'); + + if (target.isNull()) + continue; + + int line = 0; + int column = 0; + + convertPosition(target.position(), &line, &column); + Link result{textDocument()->filePath(), line, column}; + result.linkTextStart = match.capturedStart(CAPTURE_GROUP_ANCHOR) + blockOffset; + result.linkTextEnd = match.capturedEnd(CAPTURE_GROUP_ANCHOR) + blockOffset; + processLinkCallback(result); + break; } else { QTC_ASSERT_STRING("This line should not be reached unless 'markdownLink' is wrong"); return;