Refactor render system (#32492)
There were too many patches to the Render system, it's really difficult to make further improvements. This PR clears the legacy problems and fix TODOs. 1. Rename `RenderContext.Type` to `RenderContext.MarkupType` to clarify its usage. 2. Use `ContentMode` to replace `meta["mode"]` and `IsWiki`, to clarify the rendering behaviors. 3. Use "wiki" mode instead of "mode=gfm + wiki=true" 4. Merge `renderByType` and `renderByFile` 5. Add more comments ---- The problem of "mode=document": in many cases it is not set, so many non-comment places use comment's hard line break incorrectly
This commit is contained in:
parent
985e2a8af3
commit
3f9c3e7bc3
32 changed files with 237 additions and 257 deletions
|
@ -5,11 +5,9 @@ package markup
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -29,15 +27,44 @@ const (
|
|||
RenderMetaAsTable RenderMetaMode = "table"
|
||||
)
|
||||
|
||||
type RenderContentMode string
|
||||
|
||||
const (
|
||||
RenderContentAsDefault RenderContentMode = "" // empty means "default", no special handling, maybe just a simple "document"
|
||||
RenderContentAsComment RenderContentMode = "comment"
|
||||
RenderContentAsTitle RenderContentMode = "title"
|
||||
RenderContentAsWiki RenderContentMode = "wiki"
|
||||
)
|
||||
|
||||
var RenderBehaviorForTesting struct {
|
||||
// Markdown line break rendering has 2 default behaviors:
|
||||
// * Use hard: replace "\n" with "<br>" for comments, setting.Markdown.EnableHardLineBreakInComments=true
|
||||
// * Keep soft: "\n" for non-comments (a.k.a. documents), setting.Markdown.EnableHardLineBreakInDocuments=false
|
||||
// In history, there was a mess:
|
||||
// * The behavior was controlled by `Metas["mode"] != "document",
|
||||
// * However, many places render the content without setting "mode" in Metas, all these places used comment line break setting incorrectly
|
||||
ForceHardLineBreak bool
|
||||
|
||||
// Gitea will emit some internal attributes for various purposes, these attributes don't affect rendering.
|
||||
// But there are too many hard-coded test cases, to avoid changing all of them again and again, we can disable emitting these internal attributes.
|
||||
DisableInternalAttributes bool
|
||||
}
|
||||
|
||||
// RenderContext represents a render context
|
||||
type RenderContext struct {
|
||||
Ctx context.Context
|
||||
RelativePath string // relative path from tree root of the branch
|
||||
Type string
|
||||
IsWiki bool
|
||||
Links Links
|
||||
Metas map[string]string // user, repo, mode(comment/document)
|
||||
DefaultLink string
|
||||
Ctx context.Context
|
||||
RelativePath string // relative path from tree root of the branch
|
||||
|
||||
// eg: "orgmode", "asciicast", "console"
|
||||
// for file mode, it could be left as empty, and will be detected by file extension in RelativePath
|
||||
MarkupType string
|
||||
|
||||
// what the content will be used for: eg: for comment or for wiki? or just render a file?
|
||||
ContentMode RenderContentMode
|
||||
|
||||
Links Links // special link references for rendering, especially when there is a branch/tree path
|
||||
Metas map[string]string // user&repo, format&style®exp (for external issue pattern), teams&org (for mention), BranchNameSubURL(for iframe&asciicast)
|
||||
DefaultLink string // TODO: need to figure out
|
||||
GitRepo *git.Repository
|
||||
Repo gitrepo.Repository
|
||||
ShaExistCache map[string]bool
|
||||
|
@ -77,12 +104,29 @@ func (ctx *RenderContext) AddCancel(fn func()) {
|
|||
|
||||
// Render renders markup file to HTML with all specific handling stuff.
|
||||
func Render(ctx *RenderContext, input io.Reader, output io.Writer) error {
|
||||
if ctx.Type != "" {
|
||||
return renderByType(ctx, input, output)
|
||||
} else if ctx.RelativePath != "" {
|
||||
return renderFile(ctx, input, output)
|
||||
if ctx.MarkupType == "" && ctx.RelativePath != "" {
|
||||
ctx.MarkupType = DetectMarkupTypeByFileName(ctx.RelativePath)
|
||||
if ctx.MarkupType == "" {
|
||||
return util.NewInvalidArgumentErrorf("unsupported file to render: %q", ctx.RelativePath)
|
||||
}
|
||||
}
|
||||
return errors.New("render options both filename and type missing")
|
||||
|
||||
renderer := renderers[ctx.MarkupType]
|
||||
if renderer == nil {
|
||||
return util.NewInvalidArgumentErrorf("unsupported markup type: %q", ctx.MarkupType)
|
||||
}
|
||||
|
||||
if ctx.RelativePath != "" {
|
||||
if externalRender, ok := renderer.(ExternalRenderer); ok && externalRender.DisplayInIFrame() {
|
||||
if !ctx.InStandalonePage {
|
||||
// for an external "DisplayInIFrame" render, it could only output its content in a standalone page
|
||||
// otherwise, a <iframe> should be outputted to embed the external rendered page
|
||||
return renderIFrame(ctx, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return render(ctx, renderer, input, output)
|
||||
}
|
||||
|
||||
// RenderString renders Markup string to HTML with all specific handling stuff and return string
|
||||
|
@ -170,42 +214,6 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr
|
|||
return err
|
||||
}
|
||||
|
||||
func renderByType(ctx *RenderContext, input io.Reader, output io.Writer) error {
|
||||
if renderer, ok := renderers[ctx.Type]; ok {
|
||||
return render(ctx, renderer, input, output)
|
||||
}
|
||||
return fmt.Errorf("unsupported render type: %s", ctx.Type)
|
||||
}
|
||||
|
||||
// ErrUnsupportedRenderExtension represents the error when extension doesn't supported to render
|
||||
type ErrUnsupportedRenderExtension struct {
|
||||
Extension string
|
||||
}
|
||||
|
||||
func IsErrUnsupportedRenderExtension(err error) bool {
|
||||
_, ok := err.(ErrUnsupportedRenderExtension)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUnsupportedRenderExtension) Error() string {
|
||||
return fmt.Sprintf("Unsupported render extension: %s", err.Extension)
|
||||
}
|
||||
|
||||
func renderFile(ctx *RenderContext, input io.Reader, output io.Writer) error {
|
||||
extension := strings.ToLower(filepath.Ext(ctx.RelativePath))
|
||||
if renderer, ok := extRenderers[extension]; ok {
|
||||
if r, ok := renderer.(ExternalRenderer); ok && r.DisplayInIFrame() {
|
||||
if !ctx.InStandalonePage {
|
||||
// for an external render, it could only output its content in a standalone page
|
||||
// otherwise, a <iframe> should be outputted to embed the external rendered page
|
||||
return renderIFrame(ctx, output)
|
||||
}
|
||||
}
|
||||
return render(ctx, renderer, input, output)
|
||||
}
|
||||
return ErrUnsupportedRenderExtension{extension}
|
||||
}
|
||||
|
||||
// Init initializes the render global variables
|
||||
func Init(ph *ProcessorHelper) {
|
||||
if ph != nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue