You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

orgmode.go 3.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package markup
  5. import (
  6. "bytes"
  7. "fmt"
  8. "html"
  9. "strings"
  10. "code.gitea.io/gitea/modules/log"
  11. "code.gitea.io/gitea/modules/markup"
  12. "code.gitea.io/gitea/modules/util"
  13. "github.com/niklasfasching/go-org/org"
  14. )
  15. func init() {
  16. markup.RegisterParser(Parser{})
  17. }
  18. // Parser implements markup.Parser for orgmode
  19. type Parser struct {
  20. }
  21. // Name implements markup.Parser
  22. func (Parser) Name() string {
  23. return "orgmode"
  24. }
  25. // Extensions implements markup.Parser
  26. func (Parser) Extensions() []string {
  27. return []string{".org"}
  28. }
  29. // Render renders orgmode rawbytes to HTML
  30. func Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte {
  31. htmlWriter := org.NewHTMLWriter()
  32. renderer := &Renderer{
  33. HTMLWriter: htmlWriter,
  34. URLPrefix: urlPrefix,
  35. IsWiki: isWiki,
  36. }
  37. htmlWriter.ExtendingWriter = renderer
  38. res, err := org.New().Silent().Parse(bytes.NewReader(rawBytes), "").Write(renderer)
  39. if err != nil {
  40. log.Error("Panic in orgmode.Render: %v Just returning the rawBytes", err)
  41. return rawBytes
  42. }
  43. return []byte(res)
  44. }
  45. // RenderString reners orgmode string to HTML string
  46. func RenderString(rawContent string, urlPrefix string, metas map[string]string, isWiki bool) string {
  47. return string(Render([]byte(rawContent), urlPrefix, metas, isWiki))
  48. }
  49. // Render reners orgmode string to HTML string
  50. func (Parser) Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte {
  51. return Render(rawBytes, urlPrefix, metas, isWiki)
  52. }
  53. // Renderer implements org.Writer
  54. type Renderer struct {
  55. *org.HTMLWriter
  56. URLPrefix string
  57. IsWiki bool
  58. }
  59. var byteMailto = []byte("mailto:")
  60. // WriteRegularLink renders images, links or videos
  61. func (r *Renderer) WriteRegularLink(l org.RegularLink) {
  62. link := []byte(html.EscapeString(l.URL))
  63. if l.Protocol == "file" {
  64. link = link[len("file:"):]
  65. }
  66. if len(link) > 0 && !markup.IsLink(link) &&
  67. link[0] != '#' && !bytes.HasPrefix(link, byteMailto) {
  68. lnk := string(link)
  69. if r.IsWiki {
  70. lnk = util.URLJoin("wiki", lnk)
  71. }
  72. link = []byte(util.URLJoin(r.URLPrefix, lnk))
  73. }
  74. description := string(link)
  75. if l.Description != nil {
  76. description = r.nodesAsString(l.Description...)
  77. }
  78. switch l.Kind() {
  79. case "image":
  80. r.WriteString(fmt.Sprintf(`<img src="%s" alt="%s" title="%s" />`, link, description, description))
  81. case "video":
  82. r.WriteString(fmt.Sprintf(`<video src="%s" title="%s">%s</video>`, link, description, description))
  83. default:
  84. r.WriteString(fmt.Sprintf(`<a href="%s" title="%s">%s</a>`, link, description, description))
  85. }
  86. }
  87. func (r *Renderer) emptyClone() *Renderer {
  88. wcopy := *(r.HTMLWriter)
  89. wcopy.Builder = strings.Builder{}
  90. rcopy := *r
  91. rcopy.HTMLWriter = &wcopy
  92. wcopy.ExtendingWriter = &rcopy
  93. return &rcopy
  94. }
  95. func (r *Renderer) nodesAsString(nodes ...org.Node) string {
  96. tmp := r.emptyClone()
  97. org.WriteNodes(tmp, nodes...)
  98. return tmp.String()
  99. }