From ade5da20dfcc224f8139fdb74855760a40c077b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mickae=CC=88l=20Menu?= Date: Fri, 12 Feb 2021 19:34:04 +0100 Subject: [PATCH] Support Markdown autolinking for external links --- adapter/markdown/markdown.go | 45 ++++++++++++++++++++++++------- adapter/markdown/markdown_test.go | 16 +++++++++++ go.mod | 1 + go.sum | 2 ++ 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/adapter/markdown/markdown.go b/adapter/markdown/markdown.go index fbc5956..712daf3 100644 --- a/adapter/markdown/markdown.go +++ b/adapter/markdown/markdown.go @@ -8,9 +8,11 @@ import ( "github.com/mickael-menu/zk/core/note" "github.com/mickael-menu/zk/util/opt" strutil "github.com/mickael-menu/zk/util/strings" + "github.com/mvdan/xurls" "github.com/yuin/goldmark" meta "github.com/yuin/goldmark-meta" "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" ) @@ -26,6 +28,15 @@ func NewParser() *Parser { md: goldmark.New( goldmark.WithExtensions( meta.Meta, + extension.NewLinkify( + extension.WithLinkifyAllowedProtocols([][]byte{ + []byte("http:"), + []byte("https:"), + }), + extension.WithLinkifyURLRegexp( + xurls.Strict, + ), + ), ), ), } @@ -127,16 +138,30 @@ func parseLinks(root ast.Node, source []byte) ([]note.Link, error) { links := make([]note.Link, 0) err := ast.Walk(root, func(n ast.Node, entering bool) (ast.WalkStatus, error) { - if link, ok := n.(*ast.Link); ok && entering { - href := string(link.Destination) - if href != "" { - links = append(links, note.Link{ - Title: string(link.Text(source)), - Href: href, - Rels: strings.Fields(string(link.Title)), - External: strutil.IsURL(href), - Snippet: extractLines(n.Parent(), source), - }) + if entering { + switch link := n.(type) { + case *ast.Link: + href := string(link.Destination) + if href != "" { + links = append(links, note.Link{ + Title: string(link.Text(source)), + Href: href, + Rels: strings.Fields(string(link.Title)), + External: strutil.IsURL(href), + Snippet: extractLines(n.Parent(), source), + }) + } + + case *ast.AutoLink: + if href := string(link.URL(source)); href != "" && link.AutoLinkType == ast.AutoLinkURL { + links = append(links, note.Link{ + Title: string(link.Label(source)), + Href: href, + Rels: []string{}, + External: true, + Snippet: extractLines(n.Parent(), source), + }) + } } } return ast.WalkContinue, nil diff --git a/adapter/markdown/markdown_test.go b/adapter/markdown/markdown_test.go index 8f5bce8..c635349 100644 --- a/adapter/markdown/markdown_test.go +++ b/adapter/markdown/markdown_test.go @@ -168,6 +168,8 @@ func TestParseLinks(t *testing.T) { Paragraph containing [multiple **links**](stripped-formatting), here's one [relative](../other). A link can have [one relation](one "rel-1") or [several relations](several "rel-1 rel-2"). +An https://inline-link.com and http://another-inline-link.com. + [External links](http://example.com) are marked [as such](ftp://domain). `, []note.Link{ { @@ -209,6 +211,20 @@ A link can have [one relation](one "rel-1") or [several relations](several "rel- Snippet: `Paragraph containing [multiple **links**](stripped-formatting), here's one [relative](../other). A link can have [one relation](one "rel-1") or [several relations](several "rel-1 rel-2").`, }, + { + Title: "https://inline-link.com", + Href: "https://inline-link.com", + External: true, + Rels: []string{}, + Snippet: "An https://inline-link.com and http://another-inline-link.com.", + }, + { + Title: "http://another-inline-link.com", + Href: "http://another-inline-link.com", + External: true, + Rels: []string{}, + Snippet: "An https://inline-link.com and http://another-inline-link.com.", + }, { Title: "External links", Href: "http://example.com", diff --git a/go.mod b/go.mod index e4b900a..c5dc844 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/mattn/go-runewidth v0.0.10 // indirect github.com/mattn/go-sqlite3 v1.14.6 github.com/mickael-menu/pretty v0.2.3 + github.com/mvdan/xurls v1.1.0 github.com/pelletier/go-toml v1.8.1 github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect diff --git a/go.sum b/go.sum index 3d9b994..2de8766 100644 --- a/go.sum +++ b/go.sum @@ -133,6 +133,8 @@ github.com/mickael-menu/pretty v0.2.3 h1:AXi5WcBuWxwQV6iY/GhmCFpaoboQO2SLtzfujrn github.com/mickael-menu/pretty v0.2.3/go.mod h1:gupeWUSWoo3KX7BItIuouLgTqQLlmRylpaPdIK6IqLk= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww= +github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=