本站源代码
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

261 lines
7.6KB

  1. // Copyright 2019 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 mdstripper
  5. import (
  6. "bytes"
  7. "github.com/russross/blackfriday"
  8. )
  9. // MarkdownStripper extends blackfriday.Renderer
  10. type MarkdownStripper struct {
  11. blackfriday.Renderer
  12. links []string
  13. coallesce bool
  14. }
  15. const (
  16. blackfridayExtensions = 0 |
  17. blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
  18. blackfriday.EXTENSION_TABLES |
  19. blackfriday.EXTENSION_FENCED_CODE |
  20. blackfriday.EXTENSION_STRIKETHROUGH |
  21. blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK |
  22. blackfriday.EXTENSION_DEFINITION_LISTS |
  23. blackfriday.EXTENSION_FOOTNOTES |
  24. blackfriday.EXTENSION_HEADER_IDS |
  25. blackfriday.EXTENSION_AUTO_HEADER_IDS |
  26. // Not included in modules/markup/markdown/markdown.go;
  27. // required here to process inline links
  28. blackfriday.EXTENSION_AUTOLINK
  29. )
  30. //revive:disable:var-naming Implementing the Rendering interface requires breaking some linting rules
  31. // StripMarkdown parses markdown content by removing all markup and code blocks
  32. // in order to extract links and other references
  33. func StripMarkdown(rawBytes []byte) (string, []string) {
  34. stripper := &MarkdownStripper{
  35. links: make([]string, 0, 10),
  36. }
  37. body := blackfriday.Markdown(rawBytes, stripper, blackfridayExtensions)
  38. return string(body), stripper.GetLinks()
  39. }
  40. // StripMarkdownBytes parses markdown content by removing all markup and code blocks
  41. // in order to extract links and other references
  42. func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) {
  43. stripper := &MarkdownStripper{
  44. links: make([]string, 0, 10),
  45. }
  46. body := blackfriday.Markdown(rawBytes, stripper, blackfridayExtensions)
  47. return body, stripper.GetLinks()
  48. }
  49. // block-level callbacks
  50. // BlockCode dummy function to proceed with rendering
  51. func (r *MarkdownStripper) BlockCode(out *bytes.Buffer, text []byte, infoString string) {
  52. // Not rendered
  53. r.coallesce = false
  54. }
  55. // BlockQuote dummy function to proceed with rendering
  56. func (r *MarkdownStripper) BlockQuote(out *bytes.Buffer, text []byte) {
  57. // FIXME: perhaps it's better to leave out block quote for this?
  58. r.processString(out, text, false)
  59. }
  60. // BlockHtml dummy function to proceed with rendering
  61. func (r *MarkdownStripper) BlockHtml(out *bytes.Buffer, text []byte) { //nolint
  62. // Not rendered
  63. r.coallesce = false
  64. }
  65. // Header dummy function to proceed with rendering
  66. func (r *MarkdownStripper) Header(out *bytes.Buffer, text func() bool, level int, id string) {
  67. text()
  68. r.coallesce = false
  69. }
  70. // HRule dummy function to proceed with rendering
  71. func (r *MarkdownStripper) HRule(out *bytes.Buffer) {
  72. // Not rendered
  73. r.coallesce = false
  74. }
  75. // List dummy function to proceed with rendering
  76. func (r *MarkdownStripper) List(out *bytes.Buffer, text func() bool, flags int) {
  77. text()
  78. r.coallesce = false
  79. }
  80. // ListItem dummy function to proceed with rendering
  81. func (r *MarkdownStripper) ListItem(out *bytes.Buffer, text []byte, flags int) {
  82. r.processString(out, text, false)
  83. }
  84. // Paragraph dummy function to proceed with rendering
  85. func (r *MarkdownStripper) Paragraph(out *bytes.Buffer, text func() bool) {
  86. text()
  87. r.coallesce = false
  88. }
  89. // Table dummy function to proceed with rendering
  90. func (r *MarkdownStripper) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
  91. r.processString(out, header, false)
  92. r.processString(out, body, false)
  93. }
  94. // TableRow dummy function to proceed with rendering
  95. func (r *MarkdownStripper) TableRow(out *bytes.Buffer, text []byte) {
  96. r.processString(out, text, false)
  97. }
  98. // TableHeaderCell dummy function to proceed with rendering
  99. func (r *MarkdownStripper) TableHeaderCell(out *bytes.Buffer, text []byte, flags int) {
  100. r.processString(out, text, false)
  101. }
  102. // TableCell dummy function to proceed with rendering
  103. func (r *MarkdownStripper) TableCell(out *bytes.Buffer, text []byte, flags int) {
  104. r.processString(out, text, false)
  105. }
  106. // Footnotes dummy function to proceed with rendering
  107. func (r *MarkdownStripper) Footnotes(out *bytes.Buffer, text func() bool) {
  108. text()
  109. }
  110. // FootnoteItem dummy function to proceed with rendering
  111. func (r *MarkdownStripper) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
  112. r.processString(out, text, false)
  113. }
  114. // TitleBlock dummy function to proceed with rendering
  115. func (r *MarkdownStripper) TitleBlock(out *bytes.Buffer, text []byte) {
  116. r.processString(out, text, false)
  117. }
  118. // Span-level callbacks
  119. // AutoLink dummy function to proceed with rendering
  120. func (r *MarkdownStripper) AutoLink(out *bytes.Buffer, link []byte, kind int) {
  121. r.processLink(out, link, []byte{})
  122. }
  123. // CodeSpan dummy function to proceed with rendering
  124. func (r *MarkdownStripper) CodeSpan(out *bytes.Buffer, text []byte) {
  125. // Not rendered
  126. r.coallesce = false
  127. }
  128. // DoubleEmphasis dummy function to proceed with rendering
  129. func (r *MarkdownStripper) DoubleEmphasis(out *bytes.Buffer, text []byte) {
  130. r.processString(out, text, false)
  131. }
  132. // Emphasis dummy function to proceed with rendering
  133. func (r *MarkdownStripper) Emphasis(out *bytes.Buffer, text []byte) {
  134. r.processString(out, text, false)
  135. }
  136. // Image dummy function to proceed with rendering
  137. func (r *MarkdownStripper) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
  138. // Not rendered
  139. r.coallesce = false
  140. }
  141. // LineBreak dummy function to proceed with rendering
  142. func (r *MarkdownStripper) LineBreak(out *bytes.Buffer) {
  143. // Not rendered
  144. r.coallesce = false
  145. }
  146. // Link dummy function to proceed with rendering
  147. func (r *MarkdownStripper) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
  148. r.processLink(out, link, content)
  149. }
  150. // RawHtmlTag dummy function to proceed with rendering
  151. func (r *MarkdownStripper) RawHtmlTag(out *bytes.Buffer, tag []byte) { //nolint
  152. // Not rendered
  153. r.coallesce = false
  154. }
  155. // TripleEmphasis dummy function to proceed with rendering
  156. func (r *MarkdownStripper) TripleEmphasis(out *bytes.Buffer, text []byte) {
  157. r.processString(out, text, false)
  158. }
  159. // StrikeThrough dummy function to proceed with rendering
  160. func (r *MarkdownStripper) StrikeThrough(out *bytes.Buffer, text []byte) {
  161. r.processString(out, text, false)
  162. }
  163. // FootnoteRef dummy function to proceed with rendering
  164. func (r *MarkdownStripper) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
  165. // Not rendered
  166. r.coallesce = false
  167. }
  168. // Low-level callbacks
  169. // Entity dummy function to proceed with rendering
  170. func (r *MarkdownStripper) Entity(out *bytes.Buffer, entity []byte) {
  171. // FIXME: literal entities are not parsed; perhaps they should
  172. r.coallesce = false
  173. }
  174. // NormalText dummy function to proceed with rendering
  175. func (r *MarkdownStripper) NormalText(out *bytes.Buffer, text []byte) {
  176. r.processString(out, text, true)
  177. }
  178. // Header and footer
  179. // DocumentHeader dummy function to proceed with rendering
  180. func (r *MarkdownStripper) DocumentHeader(out *bytes.Buffer) {
  181. r.coallesce = false
  182. }
  183. // DocumentFooter dummy function to proceed with rendering
  184. func (r *MarkdownStripper) DocumentFooter(out *bytes.Buffer) {
  185. r.coallesce = false
  186. }
  187. // GetFlags returns rendering flags
  188. func (r *MarkdownStripper) GetFlags() int {
  189. return 0
  190. }
  191. //revive:enable:var-naming
  192. func doubleSpace(out *bytes.Buffer) {
  193. if out.Len() > 0 {
  194. out.WriteByte('\n')
  195. }
  196. }
  197. func (r *MarkdownStripper) processString(out *bytes.Buffer, text []byte, coallesce bool) {
  198. // Always break-up words
  199. if !coallesce || !r.coallesce {
  200. doubleSpace(out)
  201. }
  202. out.Write(text)
  203. r.coallesce = coallesce
  204. }
  205. func (r *MarkdownStripper) processLink(out *bytes.Buffer, link []byte, content []byte) {
  206. // Links are processed out of band
  207. r.links = append(r.links, string(link))
  208. r.coallesce = false
  209. }
  210. // GetLinks returns the list of link data collected while parsing
  211. func (r *MarkdownStripper) GetLinks() []string {
  212. return r.links
  213. }
上海开阖软件有限公司 沪ICP备12045867号-1