mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-08 14:03:24 +09:00
refactor: render highlight language (#38793)
Avoid CSS injection More details are in the comment of CodeBlockAttributes
This commit is contained in:
@@ -8,8 +8,10 @@ import (
|
||||
"bytes"
|
||||
gohtml "html"
|
||||
"html/template"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gitea.dev/modules/htmlutil"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/util"
|
||||
@@ -161,3 +163,51 @@ func formatLexerName(name string) string {
|
||||
}
|
||||
return util.ToTitleCaseNoLower(name)
|
||||
}
|
||||
|
||||
func languageForCssAttrName(lang string) (forCSS, forAttr string) {
|
||||
s := strings.ToLower(lang)
|
||||
if s == "" || s == LanguagePlaintext || s == chromaLexerFallback {
|
||||
return "text", "text"
|
||||
}
|
||||
isValid := func(c byte) bool {
|
||||
// although "-" is valid in CSS name, it is used as a field separator, so we don't want to keep it in the name
|
||||
return 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_'
|
||||
}
|
||||
idx := 0
|
||||
for ; idx < len(s); idx++ {
|
||||
if !isValid(s[idx]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if idx == len(s) {
|
||||
return s, lang
|
||||
}
|
||||
out := []byte(s)
|
||||
for i := idx; i < len(s); i++ {
|
||||
if !isValid(out[i]) {
|
||||
out[i] = '_'
|
||||
}
|
||||
}
|
||||
return string(out), lang
|
||||
}
|
||||
|
||||
func CodeBlockAttributes(lang string) (preAttrs, codeAttrs template.HTML) {
|
||||
// Code block's "chroma" class is used to highlight the code.
|
||||
// "language-{LanguageName}" class is used as part of commonmark spec.
|
||||
// It's unclear about how to handle special chars for a language name like "Visual Basic.NET" or "C++" or "F#".
|
||||
// The commonmark spec seems wrong: https://spec.commonmark.org/0.31.2/#info-string, it just outputs invalid CSS class names.
|
||||
|
||||
cssName, attrLang := languageForCssAttrName(lang)
|
||||
renderByFrontend := lang == "mermaid" || lang == "math"
|
||||
preExtraClasses := ""
|
||||
if renderByFrontend {
|
||||
preExtraClasses = " is-loading"
|
||||
}
|
||||
|
||||
// The "math.ts" strictly depends on the structure: <pre class="code-block"><code class="language-math">...</code></pre>
|
||||
// * If "pre" exists, it is rendered as "block", otherwise, it is rendered as "inline"
|
||||
// The "mermaid.ts" also strictly depends on the structure: "pre" must exist because it is always rendered as "block".
|
||||
//
|
||||
// Hint: "data-code-language" is not exposed in some cases due to the Markup sanitizer, the rules can be refactored in the future if the attribute is useful.
|
||||
return htmlutil.HTMLFormat(`class="code-block%s"`, preExtraClasses), htmlutil.HTMLFormat(`class="chroma language-%s" data-code-language="%s"`, cssName, attrLang)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user