Source File
linkify.go
Belonging Package
github.com/yuin/goldmark/extension
package extension
import (
)
var wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?:[/#?][-a-zA-Z0-9@:%_\+.~#!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
var urlRegexp = regexp.MustCompile(`^(?:http|https|ftp)://[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?::\d+)?(?:[/#?][-a-zA-Z0-9@:%_+.~#$!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
type LinkifyConfig struct {
AllowedProtocols [][]byte
URLRegexp *regexp.Regexp
WWWRegexp *regexp.Regexp
EmailRegexp *regexp.Regexp
}
const (
optLinkifyAllowedProtocols parser.OptionName = "LinkifyAllowedProtocols"
optLinkifyURLRegexp parser.OptionName = "LinkifyURLRegexp"
optLinkifyWWWRegexp parser.OptionName = "LinkifyWWWRegexp"
optLinkifyEmailRegexp parser.OptionName = "LinkifyEmailRegexp"
)
func ( *LinkifyConfig) ( parser.OptionName, interface{}) {
switch {
case optLinkifyAllowedProtocols:
.AllowedProtocols = .([][]byte)
case optLinkifyURLRegexp:
.URLRegexp = .(*regexp.Regexp)
case optLinkifyWWWRegexp:
.WWWRegexp = .(*regexp.Regexp)
case optLinkifyEmailRegexp:
.EmailRegexp = .(*regexp.Regexp)
}
}
type LinkifyOption interface {
parser.Option
SetLinkifyOption(*LinkifyConfig)
}
type withLinkifyAllowedProtocols struct {
value [][]byte
}
func ( *withLinkifyAllowedProtocols) ( *parser.Config) {
.Options[optLinkifyAllowedProtocols] = .value
}
func ( *withLinkifyAllowedProtocols) ( *LinkifyConfig) {
.AllowedProtocols = .value
}
func ( [][]byte) LinkifyOption {
return &withLinkifyAllowedProtocols{
value: ,
}
}
type withLinkifyURLRegexp struct {
value *regexp.Regexp
}
func ( *withLinkifyURLRegexp) ( *parser.Config) {
.Options[optLinkifyURLRegexp] = .value
}
func ( *withLinkifyURLRegexp) ( *LinkifyConfig) {
.URLRegexp = .value
}
func ( *regexp.Regexp) LinkifyOption {
return &withLinkifyURLRegexp{
value: ,
}
}
type withLinkifyWWWRegexp struct {
value *regexp.Regexp
}
func ( *withLinkifyWWWRegexp) ( *parser.Config) {
.Options[optLinkifyWWWRegexp] = .value
}
func ( *withLinkifyWWWRegexp) ( *LinkifyConfig) {
.WWWRegexp = .value
}
func ( *regexp.Regexp) LinkifyOption {
return &withLinkifyWWWRegexp{
value: ,
}
}
type withLinkifyEmailRegexp struct {
value *regexp.Regexp
}
func ( *withLinkifyEmailRegexp) ( *parser.Config) {
.Options[optLinkifyEmailRegexp] = .value
}
func ( *withLinkifyEmailRegexp) ( *LinkifyConfig) {
.EmailRegexp = .value
}
func ( *regexp.Regexp) LinkifyOption {
return &withLinkifyEmailRegexp{
value: ,
}
}
type linkifyParser struct {
LinkifyConfig
}
func ( ...LinkifyOption) parser.InlineParser {
:= &linkifyParser{
LinkifyConfig: LinkifyConfig{
AllowedProtocols: nil,
URLRegexp: urlRegexp,
WWWRegexp: wwwURLRegxp,
},
}
for , := range {
.SetLinkifyOption(&.LinkifyConfig)
}
return
}
return []byte{' ', '*', '_', '~', '('}
}
var (
protoHTTP = []byte("http:")
protoHTTPS = []byte("https:")
protoFTP = []byte("ftp:")
domainWWW = []byte("www.")
)
func ( *linkifyParser) ( ast.Node, text.Reader, parser.Context) ast.Node {
if .IsInLinkLabel() {
return nil
}
, := .PeekLine()
:= 0
:= .Start
if == ' ' || == '*' || == '_' || == '~' || == '(' {
++
++
= [1:]
}
var []int
var []byte
var ast.AutoLinkType = ast.AutoLinkURL
if .LinkifyConfig.AllowedProtocols == nil {
if bytes.HasPrefix(, protoHTTP) || bytes.HasPrefix(, protoHTTPS) || bytes.HasPrefix(, protoFTP) {
= .LinkifyConfig.URLRegexp.FindSubmatchIndex()
}
} else {
for , := range .LinkifyConfig.AllowedProtocols {
if bytes.HasPrefix(, ) {
= .LinkifyConfig.URLRegexp.FindSubmatchIndex()
break
}
}
}
if == nil && bytes.HasPrefix(, domainWWW) {
= .LinkifyConfig.WWWRegexp.FindSubmatchIndex()
= []byte("http")
}
if != nil && [0] != 0 {
= nil
}
if != nil && [0] == 0 {
:= [[1]-1]
if == '.' {
[1]--
} else if == ')' {
:= 0
for := [1] - 1; >= [0]; -- {
if [] == ')' {
++
} else if [] == '(' {
--
}
}
if > 0 {
[1] -=
}
} else if == ';' {
:= [1] - 2
for ; >= [0]; -- {
if util.IsAlphaNumeric([]) {
continue
}
break
}
if != [1]-2 {
if [] == '&' {
[1] -= [1] -
}
}
}
}
if == nil {
if len() > 0 && util.IsPunct([0]) {
return nil
}
= ast.AutoLinkEmail
:= -1
if .LinkifyConfig.EmailRegexp == nil {
= util.FindEmailIndex()
} else {
:= .LinkifyConfig.EmailRegexp.FindSubmatchIndex()
if != nil && [0] == 0 {
= [1]
}
}
if < 0 {
return nil
}
:= bytes.IndexByte(, '@')
= []int{0, , , - 1}
if == nil || bytes.IndexByte([[2]:[3]], '.') < 0 {
return nil
}
:= [[1]-1]
if == '.' {
[1]--
}
if [1] < len() {
:= [[1]]
if == '-' || == '_' {
return nil
}
}
}
if == nil {
return nil
}
if != 0 {
:= .WithStop(.Start + 1)
ast.MergeOrAppendTextSegment(, )
}
+= [1]
.Advance()
:= ast.NewTextSegment(text.NewSegment(, +[1]))
:= ast.NewAutoLink(, )
.Protocol =
return
}
}
type linkify struct {
options []LinkifyOption
}
var Linkify = &linkify{}
func ( ...LinkifyOption) goldmark.Extender {
return &linkify{
options: ,
}
}
func ( *linkify) ( goldmark.Markdown) {
.Parser().AddOptions(
parser.WithInlineParsers(
util.Prioritized(NewLinkifyParser(.options...), 999),
),
)
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |