// Copyright 2015 The Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package markdown import ( "strings" "gitlab.com/golang-commonmark/linkify" ) func isLinkOpen(s string) bool { return isLetter(s[1]) } func isLinkClose(s string) bool { return s[1] == '/' } func ruleLinkify(s *StateCore) { blockTokens := s.Tokens if !s.Md.Linkify { return } for _, tok := range blockTokens { if tok, ok := tok.(*Inline); ok { tokens := tok.Children htmlLinkLevel := 0 for i := len(tokens) - 1; i >= 0; i-- { currentTok := tokens[i] if _, ok := currentTok.(*LinkClose); ok { i-- for tokens[i].Level() != currentTok.Level() { if _, ok := tokens[i].(*LinkOpen); ok { break } i-- } continue } if currentTok, ok := currentTok.(*HTMLInline); ok { if isLinkOpen(currentTok.Content) && htmlLinkLevel > 0 { htmlLinkLevel-- } if isLinkClose(currentTok.Content) { htmlLinkLevel++ } } if htmlLinkLevel > 0 { continue } if currentTok, ok := currentTok.(*Text); ok { text := currentTok.Content links := linkify.Links(text) if len(links) == 0 { continue } var nodes []Token level := currentTok.Lvl lastPos := 0 for _, ln := range links { urlText := text[ln.Start:ln.End] url := urlText if ln.Scheme == "" { url = "http://" + url } else if ln.Scheme == "mailto:" && !strings.HasPrefix(url, "mailto:") { url = "mailto:" + url } url = normalizeLink(url) if !validateLink(url) { continue } if ln.Scheme == "" { urlText = strings.TrimPrefix(normalizeLinkText("http://"+urlText), "http://") } else if ln.Scheme == "mailto:" && !strings.HasPrefix(urlText, "mailto:") { urlText = strings.TrimPrefix(normalizeLinkText("mailto:"+urlText), "mailto:") } else { urlText = normalizeLinkText(urlText) } pos := ln.Start if pos > lastPos { tok := Text{ Content: text[lastPos:pos], Lvl: level, } nodes = append(nodes, &tok) } nodes = append(nodes, &LinkOpen{ Href: url, Lvl: level, }) nodes = append(nodes, &Text{ Content: urlText, Lvl: level + 1, }) nodes = append(nodes, &LinkClose{ Lvl: level, }) lastPos = ln.End } if lastPos < len(text) { tok := Text{ Content: text[lastPos:], Lvl: level, } nodes = append(nodes, &tok) } children := make([]Token, len(tokens)+len(nodes)-1) copy(children, tokens[:i]) copy(children[i:], nodes) copy(children[i+len(nodes):], tokens[i+1:]) tok.Children = children tokens = children } } } } }