Browse Source

#637 #738 fix markdown: render special links

- code format for #1020
Unknwon 10 năm trước cách đây
mục cha
commit
ab6b288141
1 tập tin đã thay đổi với 50 bổ sung63 xóa
  1. 50 63
      modules/base/markdown.go

+ 50 - 63
modules/base/markdown.go

@@ -15,10 +15,9 @@ import (
 	"strings"
 
 	"github.com/russross/blackfriday"
+	"golang.org/x/net/html"
 
 	"github.com/gogits/gogs/modules/setting"
-
-	"golang.org/x/net/html"
 )
 
 func isletter(c byte) bool {
@@ -109,40 +108,22 @@ func (options *CustomRender) Image(out *bytes.Buffer, link []byte, title []byte,
 }
 
 var (
-	MentionPattern     = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z_]+`)
+	MentionPattern     = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z_\.]+`)
 	commitPattern      = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`)
 	issueFullPattern   = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
-	issueIndexPattern  = regexp.MustCompile(`( |^)#[0-9]+`)
+	issueIndexPattern  = regexp.MustCompile(`( |^)#[0-9]+\b`)
 	sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
 )
 
 func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
-	buf := bytes.NewBufferString("")
-	inCodeBlock := false
-	codeBlockPrefix := []byte("```")
-	lineBreak := []byte("\n")
-	tab := []byte("\t")
-	lines := bytes.Split(rawBytes, lineBreak)
-	for _, line := range lines {
-		if bytes.HasPrefix(line, codeBlockPrefix) {
-			inCodeBlock = !inCodeBlock
-		}
-
-		if !inCodeBlock && !bytes.HasPrefix(line, tab) {
-			ms := MentionPattern.FindAll(line, -1)
-			for _, m := range ms {
-				m = bytes.TrimSpace(m)
-				line = bytes.Replace(line, m,
-					[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
-			}
-		}
-
-		buf.Write(line)
-		buf.Write(lineBreak)
+	ms := MentionPattern.FindAll(rawBytes, -1)
+	for _, m := range ms {
+		m = bytes.TrimSpace(m)
+		rawBytes = bytes.Replace(rawBytes, m,
+			[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
 	}
 
-	rawBytes = buf.Bytes()
-	ms := commitPattern.FindAll(rawBytes, -1)
+	ms = commitPattern.FindAll(rawBytes, -1)
 	for _, m := range ms {
 		m = bytes.TrimSpace(m)
 		i := strings.Index(string(m), "commit/")
@@ -181,8 +162,14 @@ func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
 func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string) []byte {
 	ms := issueIndexPattern.FindAll(rawBytes, -1)
 	for _, m := range ms {
-		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`<a href="%s/issues/%s">%s</a>`,
-			urlPrefix, strings.TrimPrefix(string(m[1:]), "#"), m)), -1)
+		var space string
+		m2 := m
+		if m2[0] == ' ' {
+			space = " "
+			m2 = m2[1:]
+		}
+		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
+			space, urlPrefix, m2[1:], m2)), 1)
 	}
 	return rawBytes
 }
@@ -219,46 +206,35 @@ func RenderRawMarkdown(body []byte, urlPrefix string) []byte {
 	return body
 }
 
-func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
-	result := RenderRawMarkdown(rawBytes, urlPrefix)
-	result = PostProcessMarkdown(result, urlPrefix)
-	result = Sanitizer.SanitizeBytes(result)
-	return result
-}
-
-func RenderMarkdownString(raw, urlPrefix string) string {
-	return string(RenderMarkdown([]byte(raw), urlPrefix))
-}
-
+// PostProcessMarkdown treats different types of HTML differently,
+// and only renders special links for plain text blocks.
 func PostProcessMarkdown(rawHtml []byte, urlPrefix string) []byte {
 	var buf bytes.Buffer
 	tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))
 	for html.ErrorToken != tokenizer.Next() {
 		token := tokenizer.Token()
 		switch token.Type {
-			case html.TextToken:
-				text := []byte(token.String())
-				text = RenderSpecialLink(text, urlPrefix)
-
-				buf.Write(text)
-
-			case html.StartTagToken:
-				buf.WriteString(token.String())
-
-				tagName := token.Data
-				// If this is an excluded tag, we skip processing all output until a close tag is encountered
-				if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) {
-					for html.ErrorToken != tokenizer.Next() {
-						token = tokenizer.Token()
-						// Copy the token to the output verbatim
-						buf.WriteString(token.String())
-						// If this is the close tag, we are done
-						if html.EndTagToken == token.Type && strings.EqualFold(tagName, token.Data) { break }
+		case html.TextToken:
+			buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix))
+
+		case html.StartTagToken:
+			buf.WriteString(token.String())
+			tagName := token.Data
+			// If this is an excluded tag, we skip processing all output until a close tag is encountered.
+			if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) {
+				for html.ErrorToken != tokenizer.Next() {
+					token = tokenizer.Token()
+					// Copy the token to the output verbatim
+					buf.WriteString(token.String())
+					// If this is the close tag, we are done
+					if html.EndTagToken == token.Type && strings.EqualFold(tagName, token.Data) {
+						break
 					}
 				}
+			}
 
-			default:
-				buf.WriteString(token.String())
+		default:
+			buf.WriteString(token.String())
 		}
 	}
 
@@ -266,7 +242,18 @@ func PostProcessMarkdown(rawHtml []byte, urlPrefix string) []byte {
 		return buf.Bytes()
 	}
 
-	// If we are not at the end of the input, then some other parsing error has occurred, so return
-	// the input verbatim.
+	// If we are not at the end of the input, then some other parsing error has occurred,
+	// so return the input verbatim.
 	return rawHtml
 }
+
+func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
+	result := RenderRawMarkdown(rawBytes, urlPrefix)
+	result = PostProcessMarkdown(result, urlPrefix)
+	result = Sanitizer.SanitizeBytes(result)
+	return result
+}
+
+func RenderMarkdownString(raw, urlPrefix string) string {
+	return string(RenderMarkdown([]byte(raw), urlPrefix))
+}