From f013209fe7461359865579a28a161bb74c3abf37 Mon Sep 17 00:00:00 2001 From: b3n Date: Tue, 18 Jun 2024 14:49:09 +0200 Subject: [PATCH] Shorter default text link for attachments, comments and milestones (#22) Signed-off-by: Benoit Donneaux --- markdown/link.go | 50 ++++++++++++++++++++++++--------- markdown/link_test.go | 64 +++++++++++++++++++++++++++++++------------ 2 files changed, 84 insertions(+), 30 deletions(-) diff --git a/markdown/link.go b/markdown/link.go index 7f8d5cb..37492e8 100644 --- a/markdown/link.go +++ b/markdown/link.go @@ -36,14 +36,14 @@ var ( localFileLinkRegexp = regexp.MustCompile(`^[[:alnum:]-._,]+\.[[:alpha:]]+$`) // regexp for a trac 'comment:' and 'comment::ticket:' link: $1=commentNum, $2=ticketID - ticketCommentLinkRegexp = regexp.MustCompile(`comment:([[:digit:]]+)(?::ticket:([[:digit:]]+))?`) + ticketCommentLinkRegexp = regexp.MustCompile(`(.{0,1})comment:([[:digit:]]+)(?::ticket:([[:digit:]]+))?`) // regexp for a trac 'milestone:' link: $1=milestoneName - milestoneLinkRegexp = regexp.MustCompile(`milestone:([[:alnum:]\-._~:/?#@!$&'"()*+,;%=]+)`) + milestoneLinkRegexp = regexp.MustCompile(`(.{0,1})milestone:([[:alnum:]\-._~:/?#@!$&'"()*+,;%=]+)`) // regexp for a trac 'attachment:', 'attachment::wiki:' and 'attachment::ticket:' links: $1=file, $2=pageName, $3=ticketID attachmentLinkRegexp = regexp.MustCompile( - `attachment:([[:alnum:]\-._~/?#@!$&'"()*+,;%=]+)` + + `(.{0,1})attachment:([[:alnum:]\-._~/?#@!$&'"()*+,;%=]+)` + `(?:` + `(?::wiki:((?:[[:upper:]][[:lower:]]*)+))|` + `(?::ticket:([[:digit:]]+))` + @@ -100,7 +100,8 @@ func (converter *DefaultConverter) resolveHtdocsLink(link string) string { } func (converter *DefaultConverter) resolveTicketCommentLink(ticketID int64, link string) string { - commentNumStr := ticketCommentLinkRegexp.ReplaceAllString(link, `$1`) + leadingChar := ticketCommentLinkRegexp.ReplaceAllString(link, `$1`) + commentNumStr := ticketCommentLinkRegexp.ReplaceAllString(link, `$2`) var commentNum int64 commentNum, err := strconv.ParseInt(commentNumStr, 10, 64) if err != nil { @@ -108,7 +109,7 @@ func (converter *DefaultConverter) resolveTicketCommentLink(ticketID int64, link return link } - commentTicketIDStr := ticketCommentLinkRegexp.ReplaceAllString(link, `$2`) + commentTicketIDStr := ticketCommentLinkRegexp.ReplaceAllString(link, `$3`) var commentTicketID int64 if commentTicketIDStr != "" { commentTicketID, err = strconv.ParseInt(commentTicketIDStr, 10, 64) @@ -145,11 +146,17 @@ func (converter *DefaultConverter) resolveTicketCommentLink(ticketID int64, link } commentURL := converter.giteaAccessor.GetIssueCommentURL(commentTicketID, commentID) - return markLink(commentURL) + + // unless already defined before, use a short link text instead of the full URL + if leadingChar != "]" { + return leadingChar + "[comment:" + strconv.FormatInt(commentID, 10) + "]" + markLink(commentURL) + } + return leadingChar + markLink(commentURL) } func (converter *DefaultConverter) resolveMilestoneLink(link string) string { - milestoneName := milestoneLinkRegexp.ReplaceAllString(link, `$1`) + leadingChar := milestoneLinkRegexp.ReplaceAllString(link, `$1`) + milestoneName := milestoneLinkRegexp.ReplaceAllString(link, `$2`) milestoneID, err := converter.giteaAccessor.GetMilestoneID(milestoneName) if err != nil { return link // not a recognised link - do not mark (error should already be logged) @@ -160,10 +167,16 @@ func (converter *DefaultConverter) resolveMilestoneLink(link string) string { } milestoneURL := converter.giteaAccessor.GetMilestoneURL(milestoneID) - return markLink(milestoneURL) + + // unless already defined before, use a short link text instead of the full URL + if leadingChar != "]" { + return leadingChar + "[milestone:" + milestoneName + "]" + markLink(milestoneURL) + } + return leadingChar + markLink(milestoneURL) } func (converter *DefaultConverter) resolveTicketAttachmentLink(ticketID int64, attachmentName string, link string) string { + leadingChar := attachmentLinkRegexp.ReplaceAllString(link, `$1`) issueID, err := converter.giteaAccessor.GetIssueID(ticketID) if err != nil { return link // not a recognised link - do not mark @@ -183,19 +196,30 @@ func (converter *DefaultConverter) resolveTicketAttachmentLink(ticketID int64, a } attachmentURL := converter.giteaAccessor.GetIssueAttachmentURL(issueID, uuid) - return markLink(attachmentURL) + + // Keep original text unless already defined before + if leadingChar != "]" { + return leadingChar + "[attachment:" + attachmentName + "]" + markLink(attachmentURL) + } + return leadingChar + markLink(attachmentURL) } func (converter *DefaultConverter) resolveWikiAttachmentLink(wikiPage string, attachmentName string, link string) string { + leadingChar := attachmentLinkRegexp.ReplaceAllString(link, `$1`) attachmentWikiRelPath := converter.giteaAccessor.GetWikiAttachmentRelPath(wikiPage, attachmentName) attachmentURL := converter.giteaAccessor.GetWikiFileURL(attachmentWikiRelPath) - return markLink(attachmentURL) + + // Keep original text unless already defined before + if leadingChar != "]" { + return leadingChar + "[attachment:" + attachmentName + "]" + markLink(attachmentURL) + } + return leadingChar + markLink(attachmentURL) } func (converter *DefaultConverter) resolveAttachmentLink(ticketID int64, wikiPage string, link string) string { - attachmentName := attachmentLinkRegexp.ReplaceAllString(link, `$1`) - attachmentWikiPage := attachmentLinkRegexp.ReplaceAllString(link, `$2`) - attachmentTicketIDStr := attachmentLinkRegexp.ReplaceAllString(link, `$3`) + attachmentName := attachmentLinkRegexp.ReplaceAllString(link, `$2`) + attachmentWikiPage := attachmentLinkRegexp.ReplaceAllString(link, `$3`) + attachmentTicketIDStr := attachmentLinkRegexp.ReplaceAllString(link, `$4`) // there are two types of attachment: ticket attachments and wiki attachments... if attachmentTicketIDStr != "" { diff --git a/markdown/link_test.go b/markdown/link_test.go index 3039ff0..852eb2e 100644 --- a/markdown/link_test.go +++ b/markdown/link_test.go @@ -98,21 +98,27 @@ func verifyAllLinkTypes( convertFn func(tracText string) string, tracLinkStr string, markdownLinkStr string, - testAutomaticLinks ...bool) { + extraOptions ...string) { - // use testAutomaticLinks when the tested link should work without accompanying text - if len(testAutomaticLinks) > 0 { + // the markdown link text can be specified with the first extra option + markdownLinkText := markdownLinkStr + if len(extraOptions) > 0 && extraOptions[0] != "" { + markdownLinkText = extraOptions[0] + } + + // if a second extra option is passed, the tested link should work without accompanying text + if len(extraOptions) > 1 && extraOptions[1] == "true" { verifyLink(t, setUpFn, tearDownFn, convertFn, tracPlainLink(tracLinkStr), markdownAutomaticLink(markdownLinkStr), false) verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLink(tracLinkStr), markdownAutomaticLink(markdownLinkStr), true) verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLink(tracLinkStr), markdownAutomaticLink(markdownLinkStr), false) verifyLink(t, setUpFn, tearDownFn, convertFn, tracDoubleBracketLink(tracLinkStr), markdownAutomaticLink(markdownLinkStr), true) verifyLink(t, setUpFn, tearDownFn, convertFn, tracDoubleBracketLink(tracLinkStr), markdownAutomaticLink(markdownLinkStr), false) } else { - verifyLink(t, setUpFn, tearDownFn, convertFn, tracPlainLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkStr), false) - verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkStr), true) - verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkStr), false) - verifyLink(t, setUpFn, tearDownFn, convertFn, tracDoubleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkStr), true) - verifyLink(t, setUpFn, tearDownFn, convertFn, tracDoubleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkStr), false) + verifyLink(t, setUpFn, tearDownFn, convertFn, tracPlainLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkText), false) + verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkText), true) + verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkText), false) + verifyLink(t, setUpFn, tearDownFn, convertFn, tracDoubleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkText), true) + verifyLink(t, setUpFn, tearDownFn, convertFn, tracDoubleBracketLink(tracLinkStr), markdownLinkWithText(markdownLinkStr, markdownLinkText), false) } verifyLink(t, setUpFn, tearDownFn, convertFn, tracSingleBracketLinkWithText(tracLinkStr, linkText), markdownLinkWithText(markdownLinkStr, linkText), true) @@ -130,13 +136,29 @@ func verifyAllLinkTypes( const httpLink = "http://www.example.com" func TestHttpLinks(t *testing.T) { - verifyAllLinkTypes(t, setUp, tearDown, wikiConvert, httpLink, httpLink, true) + verifyAllLinkTypes( + t, + setUp, + tearDown, + wikiConvert, + httpLink, + httpLink, + "", + "true") } const httpsLink = "https://www.example.com" func TestHttpsLink(t *testing.T) { - verifyAllLinkTypes(t, setUp, tearDown, wikiConvert, httpsLink, httpsLink, true) + verifyAllLinkTypes( + t, + setUp, + tearDown, + wikiConvert, + httpsLink, + httpsLink, + "", + "true") } const ( @@ -282,6 +304,7 @@ const ( tracCommentNumStr = "12" commentTime int64 = 112233 commentID int64 = 54321 + commentIDStr string = "54321" commentURL string = "url-of-comment-54321" ) @@ -318,7 +341,8 @@ func TestImplicitTicketCommentLink(t *testing.T) { tearDown, ticketConvert, "comment:"+tracCommentNumStr, - commentURL) + commentURL, + "comment:"+commentIDStr) } const ( @@ -337,7 +361,8 @@ func TestExplicitTicketCommentLink(t *testing.T) { tearDown, ticketConvert, "comment:"+tracCommentNumStr+":ticket:"+otherTicketIDStr, - commentURL) + commentURL, + "comment:"+commentIDStr) } const ( @@ -369,7 +394,8 @@ func TestMilestoneLink(t *testing.T) { tearDown, wikiConvert, "milestone:"+milestoneName, - milestoneURL) + milestoneURL, + "milestone:"+milestoneName) } const ( @@ -405,7 +431,8 @@ func TestImplicitWikiAttachmentLink(t *testing.T) { tearDown, wikiConvert, "attachment:"+attachmentName, - attachmentWikiURL) + attachmentWikiURL, + "attachment:"+attachmentName) } const ( @@ -423,7 +450,8 @@ func TestExplicitWikiAttachmentLink(t *testing.T) { tearDown, wikiConvert, "attachment:"+attachmentName+":wiki:"+otherWikiPage, - attachmentWikiURL) + attachmentWikiURL, + "attachment:"+attachmentName) } const ( @@ -458,7 +486,8 @@ func TestImplicitTicketAttachmentLink(t *testing.T) { tearDown, ticketConvert, "attachment:"+attachmentName, - ticketAttachmentURL) + ticketAttachmentURL, + "attachment:"+attachmentName) } func setUpExplicitTicketAttachmentLink(t *testing.T) { @@ -472,7 +501,8 @@ func TestExplicitTicketAttachmentLink(t *testing.T) { tearDown, ticketConvert, "attachment:"+attachmentName+":ticket:"+otherTicketIDStr, - ticketAttachmentURL) + ticketAttachmentURL, + "attachment:"+attachmentName) } const (