// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package markdown import ( "bytes" "fmt" "strings" "code.gitea.io/gitea/modules/markup" "github.com/microcosm-cc/bluemonday/css" "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" ) // renderCodeSpan renders CodeSpan elements (like goldmark upstream does) but also renders ColorPreview elements. // See #21474 for reference func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { if entering { if n.Attributes() != nil { _, _ = w.WriteString("') } else { _, _ = w.WriteString("") } for c := n.FirstChild(); c != nil; c = c.NextSibling() { switch v := c.(type) { case *ast.Text: segment := v.Segment value := segment.Value(source) if bytes.HasSuffix(value, []byte("\n")) { r.Writer.RawWrite(w, value[:len(value)-1]) r.Writer.RawWrite(w, []byte(" ")) } else { r.Writer.RawWrite(w, value) } case *ColorPreview: _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) } } return ast.WalkSkipChildren, nil } _, _ = w.WriteString("") return ast.WalkContinue, nil } // cssColorHandler checks if a string is a render-able CSS color value. // The code is from "github.com/microcosm-cc/bluemonday/css.ColorHandler", except that it doesn't handle color words like "red". func cssColorHandler(value string) bool { value = strings.ToLower(value) if css.HexRGB.MatchString(value) { return true } if css.RGB.MatchString(value) { return true } if css.RGBA.MatchString(value) { return true } if css.HSL.MatchString(value) { return true } return css.HSLA.MatchString(value) } func (g *ASTTransformer) transformCodeSpan(ctx *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) { colorContent := v.Text(reader.Source()) if cssColorHandler(string(colorContent)) { v.AppendChild(v, NewColorPreview(colorContent)) } }