2014-04-10 14:20:58 -04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2018-10-30 17:26:28 -05:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2014-04-10 14:20:58 -04:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2016-02-20 17:10:05 -05:00
package markdown
2014-04-10 14:20:58 -04:00
import (
"bytes"
2019-12-31 01:53:28 +00:00
"sync"
2014-04-10 14:20:58 -04:00
2019-12-31 01:53:28 +00:00
"code.gitea.io/gitea/modules/log"
2017-04-21 15:01:08 +08:00
"code.gitea.io/gitea/modules/markup"
2019-12-31 01:53:28 +00:00
"code.gitea.io/gitea/modules/markup/common"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/setting"
2019-12-31 01:53:28 +00:00
giteautil "code.gitea.io/gitea/modules/util"
"github.com/yuin/goldmark"
2020-04-09 11:54:50 +01:00
meta "github.com/yuin/goldmark-meta"
2019-12-31 01:53:28 +00:00
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
2014-04-10 14:20:58 -04:00
)
2019-12-31 01:53:28 +00:00
var converter goldmark . Markdown
var once = sync . Once { }
2014-04-10 14:20:58 -04:00
2019-12-31 01:53:28 +00:00
var urlPrefixKey = parser . NewContextKey ( )
var isWikiKey = parser . NewContextKey ( )
2018-02-27 08:09:18 +01:00
2019-12-31 01:53:28 +00:00
// NewGiteaParseContext creates a parser.Context with the gitea context set
func NewGiteaParseContext ( urlPrefix string , isWiki bool ) parser . Context {
pc := parser . NewContext ( parser . WithIDs ( newPrefixedIDs ( ) ) )
pc . Set ( urlPrefixKey , urlPrefix )
pc . Set ( isWikiKey , isWiki )
return pc
2016-01-09 10:59:04 +08:00
}
2016-02-20 17:10:05 -05:00
// RenderRaw renders Markdown to HTML without handling special links.
2017-02-14 08:13:59 +07:00
func RenderRaw ( body [ ] byte , urlPrefix string , wikiMarkdown bool ) [ ] byte {
2019-12-31 01:53:28 +00:00
once . Do ( func ( ) {
converter = goldmark . New (
goldmark . WithExtensions ( extension . Table ,
extension . Strikethrough ,
extension . TaskList ,
extension . DefinitionList ,
common . FootnoteExtension ,
extension . NewTypographer (
extension . WithTypographicSubstitutions ( extension . TypographicSubstitutions {
2020-01-22 09:30:20 -06:00
extension . EnDash : nil ,
extension . EmDash : nil ,
extension . Ellipsis : nil ,
2019-12-31 01:53:28 +00:00
} ) ,
) ,
2020-04-09 11:54:50 +01:00
meta . New ( meta . WithTable ( ) ) ,
2019-12-31 01:53:28 +00:00
) ,
goldmark . WithParserOptions (
parser . WithAttribute ( ) ,
parser . WithAutoHeadingID ( ) ,
parser . WithASTTransformers (
util . Prioritized ( & GiteaASTTransformer { } , 10000 ) ,
) ,
) ,
goldmark . WithRendererOptions (
html . WithUnsafe ( ) ,
) ,
)
// Override the original Tasklist renderer!
converter . Renderer ( ) . AddOptions (
renderer . WithNodeRenderers (
util . Prioritized ( NewTaskCheckBoxHTMLRenderer ( ) , 1000 ) ,
) ,
)
if setting . Markdown . EnableHardLineBreak {
converter . Renderer ( ) . AddOptions ( html . WithHardWraps ( ) )
}
} )
2014-04-10 14:20:58 -04:00
2019-12-31 01:53:28 +00:00
pc := NewGiteaParseContext ( urlPrefix , wikiMarkdown )
var buf bytes . Buffer
if err := converter . Convert ( giteautil . NormalizeEOL ( body ) , & buf , parser . WithContext ( pc ) ) ; err != nil {
log . Error ( "Unable to render: %v" , err )
2015-09-01 08:32:02 -04:00
}
2019-12-31 01:53:28 +00:00
return markup . SanitizeReader ( & buf ) . Bytes ( )
2014-05-05 13:08:01 -04:00
}
2017-04-21 15:01:08 +08:00
var (
// MarkupName describes markup's name
MarkupName = "markdown"
)
func init ( ) {
markup . RegisterParser ( Parser { } )
}
// Parser implements markup.Parser
2019-12-31 01:53:28 +00:00
type Parser struct { }
2017-04-21 15:01:08 +08:00
// Name implements markup.Parser
func ( Parser ) Name ( ) string {
return MarkupName
}
// Extensions implements markup.Parser
func ( Parser ) Extensions ( ) [ ] string {
return setting . Markdown . FileExtensions
}
// Render implements markup.Parser
func ( Parser ) Render ( rawBytes [ ] byte , urlPrefix string , metas map [ string ] string , isWiki bool ) [ ] byte {
2017-09-17 01:17:57 +08:00
return RenderRaw ( rawBytes , urlPrefix , isWiki )
}
// Render renders Markdown to HTML with all specific handling stuff.
func Render ( rawBytes [ ] byte , urlPrefix string , metas map [ string ] string ) [ ] byte {
return markup . Render ( "a.md" , rawBytes , urlPrefix , metas )
}
// RenderString renders Markdown to HTML with special links and returns string type.
func RenderString ( raw , urlPrefix string , metas map [ string ] string ) string {
return markup . RenderString ( "a.md" , raw , urlPrefix , metas )
}
// RenderWiki renders markdown wiki page to HTML and return HTML string
func RenderWiki ( rawBytes [ ] byte , urlPrefix string , metas map [ string ] string ) string {
return markup . RenderWiki ( "a.md" , rawBytes , urlPrefix , metas )
}
// IsMarkdownFile reports whether name looks like a Markdown file
// based on its extension.
func IsMarkdownFile ( name string ) bool {
return markup . IsMarkupFile ( name , MarkupName )
2017-04-21 15:01:08 +08:00
}