mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package markup
|
|
|
|
import (
|
|
"io"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/hanzoai/git/modules/setting"
|
|
"github.com/hanzoai/git/modules/typesniffer"
|
|
)
|
|
|
|
// Renderer defines an interface for rendering markup file to HTML
|
|
type Renderer interface {
|
|
Name() string // markup format name, also the renderer type, also the external tool name
|
|
FileNamePatterns() []string
|
|
SanitizerRules() []setting.MarkupSanitizerRule
|
|
Render(ctx *RenderContext, input io.Reader, output io.Writer) error
|
|
}
|
|
|
|
// PostProcessRenderer defines an interface for renderers who need post process
|
|
type PostProcessRenderer interface {
|
|
NeedPostProcess() bool
|
|
}
|
|
|
|
type ExternalRendererOptions struct {
|
|
SanitizerDisabled bool
|
|
DisplayInIframe bool
|
|
ContentSandbox string
|
|
}
|
|
|
|
// ExternalRenderer defines an interface for external renderers
|
|
type ExternalRenderer interface {
|
|
GetExternalRendererOptions() ExternalRendererOptions
|
|
}
|
|
|
|
// RendererContentDetector detects if the content can be rendered
|
|
// by specified renderer
|
|
type RendererContentDetector interface {
|
|
CanRender(filename string, sniffedType typesniffer.SniffedType, prefetchBuf []byte) bool
|
|
}
|
|
|
|
var (
|
|
fileNameRenderers = make(map[string]Renderer)
|
|
renderers = make(map[string]Renderer)
|
|
)
|
|
|
|
// RegisterRenderer registers a new markup file renderer
|
|
func RegisterRenderer(renderer Renderer) {
|
|
// TODO: need to handle conflicts
|
|
renderers[renderer.Name()] = renderer
|
|
}
|
|
|
|
func RefreshFileNamePatterns() {
|
|
// TODO: need to handle conflicts
|
|
fileNameRenderers = make(map[string]Renderer)
|
|
for _, renderer := range renderers {
|
|
for _, ext := range renderer.FileNamePatterns() {
|
|
fileNameRenderers[strings.ToLower(ext)] = renderer
|
|
}
|
|
}
|
|
}
|
|
|
|
func DetectRendererTypeByFilename(filename string) Renderer {
|
|
basename := path.Base(strings.ToLower(filename))
|
|
ext1 := path.Ext(basename)
|
|
if renderer := fileNameRenderers[basename]; renderer != nil {
|
|
return renderer
|
|
}
|
|
if renderer := fileNameRenderers["*"+ext1]; renderer != nil {
|
|
return renderer
|
|
}
|
|
if basename, ok := strings.CutSuffix(basename, ext1); ok {
|
|
ext2 := path.Ext(basename)
|
|
if renderer := fileNameRenderers["*"+ext2+ext1]; renderer != nil {
|
|
return renderer
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DetectRendererTypeByPrefetch detects the markup type of the content
|
|
func DetectRendererTypeByPrefetch(filename string, sniffedType typesniffer.SniffedType, prefetchBuf []byte) string {
|
|
if filename != "" {
|
|
byExt := DetectRendererTypeByFilename(filename)
|
|
if byExt != nil {
|
|
return byExt.Name()
|
|
}
|
|
}
|
|
for _, renderer := range renderers {
|
|
if detector, ok := renderer.(RendererContentDetector); ok && detector.CanRender(filename, sniffedType, prefetchBuf) {
|
|
return renderer.Name()
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func PreviewableExtensions() []string {
|
|
exts := make([]string, 0, len(fileNameRenderers))
|
|
for p := range fileNameRenderers {
|
|
if s, ok := strings.CutPrefix(p, "*"); ok {
|
|
exts = append(exts, s)
|
|
}
|
|
}
|
|
return exts
|
|
}
|