示例#1
0
文件: render.go 项目: roktas/markdown
func (r *Renderer) renderInlineAsText(tokens []Token) {
	for _, tok := range tokens {
		if text, ok := tok.(*Text); ok {
			html.WriteEscapedString(r.w, text.Content)
		} else if img, ok := tok.(*Image); ok {
			r.renderInlineAsText(img.Tokens)
		}
	}
}
示例#2
0
文件: render.go 项目: roktas/markdown
func (r *Renderer) renderToken(tokens []Token, idx int, options RenderOptions) {
	tok := tokens[idx]

	switch tok := tok.(type) {
	case *BlockquoteClose:
		r.w.WriteString("</blockquote>")

	case *BlockquoteOpen:
		r.w.WriteString("<blockquote>")

	case *BulletListClose:
		r.w.WriteString("</ul>")

	case *BulletListOpen:
		r.w.WriteString("<ul>")

	case *CodeBlock:
		r.w.WriteString("<pre><code>")
		html.WriteEscapedString(r.w, tok.Content)
		r.w.WriteString("</code></pre>")

	case *CodeInline:
		r.w.WriteString("<code>")
		html.WriteEscapedString(r.w, tok.Content)
		r.w.WriteString("</code>")

	case *EmphasisClose:
		r.w.WriteString("</em>")

	case *EmphasisOpen:
		r.w.WriteString("<em>")

	case *Fence:
		r.w.WriteString("<pre><code")
		if tok.Params != "" {
			langName := strings.SplitN(unescapeAll(tok.Params), " ", 2)[0]
			r.w.WriteString(` class="`)
			r.w.WriteString(options.LangPrefix)
			html.WriteEscapedString(r.w, langName)
			r.w.WriteByte('"')
		}
		r.w.WriteByte('>')
		html.WriteEscapedString(r.w, tok.Content)
		r.w.WriteString("</code></pre>")

	case *Hardbreak:
		if options.XHTML {
			r.w.WriteString("<br />\n")
		} else {
			r.w.WriteString("<br>\n")
		}

	case *HeadingClose:
		r.w.WriteString("</h")
		r.w.WriteByte("0123456789"[tok.HLevel])
		r.w.WriteString(">")

	case *HeadingOpen:
		r.w.WriteString("<h")
		r.w.WriteByte("0123456789"[tok.HLevel])
		r.w.WriteByte('>')

	case *Hr:
		if options.XHTML {
			r.w.WriteString("<hr />")
		} else {
			r.w.WriteString("<hr>")
		}

	case *HTMLBlock:
		r.w.WriteString(tok.Content)
		return // no newline

	case *HTMLInline:
		r.w.WriteString(tok.Content)

	case *Image:
		r.w.WriteString(`<img src="`)
		html.WriteEscapedString(r.w, tok.Src)
		r.w.WriteString(`" alt="`)
		r.renderInlineAsText(tok.Tokens)
		r.w.WriteByte('"')

		if tok.Title != "" {
			r.w.WriteString(` title="`)
			html.WriteEscapedString(r.w, html.ReplaceEntities(tok.Title))
			r.w.WriteByte('"')
		}
		if options.XHTML {
			r.w.WriteString(" />")
		} else {
			r.w.WriteByte('>')
		}

	case *LinkClose:
		r.w.WriteString("</a>")

	case *LinkOpen:
		r.w.WriteString(`<a href="`)
		html.WriteEscapedString(r.w, tok.Href)
		r.w.WriteByte('"')
		if tok.Title != "" {
			r.w.WriteString(` title="`)
			html.WriteEscapedString(r.w, html.ReplaceEntities(tok.Title))
			r.w.WriteByte('"')
		}
		if tok.Target != "" {
			r.w.WriteString(` target="`)
			html.WriteEscapedString(r.w, tok.Target)
			r.w.WriteByte('"')
		}
		if options.Nofollow {
			r.w.WriteString(` rel="nofollow"`)
		}
		r.w.WriteByte('>')

	case *ListItemClose:
		r.w.WriteString("</li>")

	case *ListItemOpen:
		r.w.WriteString("<li>")

	case *OrderedListClose:
		r.w.WriteString("</ol>")

	case *OrderedListOpen:
		if tok.Order != 1 {
			r.w.WriteString(`<ol start="`)
			r.w.WriteString(strconv.Itoa(tok.Order))
			r.w.WriteString(`">`)
		} else {
			r.w.WriteString("<ol>")
		}

	case *ParagraphClose:
		if !tok.Tight {
			r.w.WriteString("</p>")
		} else if tokens[idx+1].Closing() {
			return // no newline
		}

	case *ParagraphOpen:
		if !tok.Tight {
			r.w.WriteString("<p>")
		}

	case *Softbreak:
		if options.Breaks {
			if options.XHTML {
				r.w.WriteString("<br />\n")
			} else {
				r.w.WriteString("<br>\n")
			}
		} else {
			r.w.WriteByte('\n')
		}
		return

	case *StrongClose:
		r.w.WriteString("</strong>")

	case *StrongOpen:
		r.w.WriteString("<strong>")

	case *StrikethroughClose:
		r.w.WriteString("</s>")

	case *StrikethroughOpen:
		r.w.WriteString("<s>")

	case *TableClose:
		r.w.WriteString("</table>")

	case *TableOpen:
		r.w.WriteString("<table>")

	case *TbodyClose:
		r.w.WriteString("</tbody>")

	case *TbodyOpen:
		r.w.WriteString("<tbody>")

	case *TdClose:
		r.w.WriteString("</td>")

	case *TdOpen:
		if tok.Align != AlignNone {
			r.w.WriteString(`<td style="text-align:`)
			r.w.WriteString(tok.Align.String())
			r.w.WriteString(`">`)
		} else {
			r.w.WriteString("<td>")
		}

	case *Text:
		html.WriteEscapedString(r.w, tok.Content)

	case *TheadClose:
		r.w.WriteString("</thead>")

	case *TheadOpen:
		r.w.WriteString("<thead>")

	case *ThClose:
		r.w.WriteString("</th>")

	case *ThOpen:
		if align := tok.Align; align != AlignNone {
			r.w.WriteString(`<th style="text-align:`)
			r.w.WriteString(align.String())
			r.w.WriteString(`">`)
		} else {
			r.w.WriteString("<th>")
		}

	case *TrClose:
		r.w.WriteString("</tr>")

	case *TrOpen:
		r.w.WriteString("<tr>")

	default:
		panic("unknown token type")
	}

	needLf := false
	if tok.Block() {
		needLf = true

		if tok.Opening() {
			nextTok := tokens[idx+1]
			switch nextTok := nextTok.(type) {
			case *Inline:
				needLf = false
			case *ParagraphOpen:
				if nextTok.Tight {
					needLf = false
				}
			case *ParagraphClose:
				if nextTok.Tight {
					needLf = false
				}
			}
			if needLf && nextTok.Closing() && nextTok.Tag() == tok.Tag() {
				needLf = false
			}
		}
	}

	if needLf {
		r.w.WriteByte('\n')
	}
}