gitea源码

transform_codespan.go 2.2KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // Copyright 2024 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package markdown
  4. import (
  5. "bytes"
  6. "strings"
  7. "code.gitea.io/gitea/modules/markup"
  8. "github.com/microcosm-cc/bluemonday/css"
  9. "github.com/yuin/goldmark/ast"
  10. "github.com/yuin/goldmark/renderer/html"
  11. "github.com/yuin/goldmark/text"
  12. "github.com/yuin/goldmark/util"
  13. )
  14. // renderCodeSpan renders CodeSpan elements (like goldmark upstream does) but also renders ColorPreview elements.
  15. // See #21474 for reference
  16. func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
  17. if entering {
  18. if n.Attributes() != nil {
  19. _, _ = w.WriteString("<code")
  20. html.RenderAttributes(w, n, html.CodeAttributeFilter)
  21. _ = w.WriteByte('>')
  22. } else {
  23. _, _ = w.WriteString("<code>")
  24. }
  25. for c := n.FirstChild(); c != nil; c = c.NextSibling() {
  26. switch v := c.(type) {
  27. case *ast.Text:
  28. segment := v.Segment
  29. value := segment.Value(source)
  30. if bytes.HasSuffix(value, []byte("\n")) {
  31. r.Writer.RawWrite(w, value[:len(value)-1])
  32. r.Writer.RawWrite(w, []byte(" "))
  33. } else {
  34. r.Writer.RawWrite(w, value)
  35. }
  36. case *ColorPreview:
  37. _ = r.renderInternal.FormatWithSafeAttrs(w, `<span class="color-preview" style="background-color: %s"></span>`, string(v.Color))
  38. }
  39. }
  40. return ast.WalkSkipChildren, nil
  41. }
  42. _, _ = w.WriteString("</code>")
  43. return ast.WalkContinue, nil
  44. }
  45. // cssColorHandler checks if a string is a render-able CSS color value.
  46. // The code is from "github.com/microcosm-cc/bluemonday/css.ColorHandler", except that it doesn't handle color words like "red".
  47. func cssColorHandler(value string) bool {
  48. value = strings.ToLower(value)
  49. if css.HexRGB.MatchString(value) {
  50. return true
  51. }
  52. if css.RGB.MatchString(value) {
  53. return true
  54. }
  55. if css.RGBA.MatchString(value) {
  56. return true
  57. }
  58. if css.HSL.MatchString(value) {
  59. return true
  60. }
  61. return css.HSLA.MatchString(value)
  62. }
  63. func (g *ASTTransformer) transformCodeSpan(_ *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) {
  64. colorContent := v.Text(reader.Source()) //nolint:staticcheck // Text is deprecated
  65. if cssColorHandler(string(colorContent)) {
  66. v.AppendChild(v, NewColorPreview(colorContent))
  67. }
  68. }